類和對象
1 面向對象的思想
面向過程:面向處理理,更多的是從計算機⻆角度思考,注重計算每⼀一個步驟,程式更
像是⼀一本cpu操作⼿手冊。
面向對象:以日常生活的角度思考問題的解決,更接近人的思維方式,讓人以從
更高的層面考慮系統的建構
以你請朋友吃飯為例:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiclRnblN2XjlGcjAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9UFVNlXTqJWMw1mYwx2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyUzN3AzMwMTMxATOwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
面向對象的優點:
面向對象更加适合做應用的開發
面向對象可以使你的代碼更加優雅和緊湊
面向對象開發效率更高
面向對象代碼複用度更高、可維護性更好
面向對象是⼀一種思維方式,它認為萬事萬物皆對象,程式是由多個對象協作共同完
成功能的,是以以後我們要從面向過程轉向面向對象。以⾯向對象的方式考慮程式
的建構。面向對象的核心是: 類和對象
問題->面向對象分析(OOA)->發現對象->類->用類實例化對象->對象協作完成功能
2. 類和對象
2.1 類和對象的概念
生活角度
類:具有相同特征和行為的對象的集合,是一個概念
對象:客觀存在的一切事物,是類的實例
類: 汽車 超級英雄 電腦 杯子
對象: 紅色的寶馬 美國隊長 桌上的mac pro 老王的⿊色杯⼦
程式角度
類:使用者自定義的資料類型,是模闆,不占⽤用記憶體
對象:由類定義的變量,占用記憶體
類:
成員屬性(成員變量) 描述對象的靜态特征,諸如,名字、身高體重
成員方法 描述對象的動态特征,例如:吃飯、睡覺、打⾖豆
2.2 類的定義
#文法:
class 類名:
類體
注意:
類定義必須以關鍵字class開頭
類名要符合辨別符的規範
類名⼀一般用大駝峰風格: 每個單詞首字⺟母大寫,其它⼩小寫 ,例如MyBook
YouMoney
類體必須縮進
在python3中類預設繼承object,是以可以這樣寫 class Dog:,它等價于class
Dog(object):
一個檔案里隻放⼀一個類
2.3 成員方法
成員方法其實就是函數,作用域在類内,成員方法的第一個參數必須是self,self
代表目前對象,也就是調⽤用這個方法的對象,這個參數由系統傳遞。
class Dog(object):
def bark(self): #成員方法,第一個參數必須是self,代表目前調用對象
print('我是小可愛--丁丁')
dingding = Dog() #實例化一個對象
#調用方法,不需要傳參數,self是系統傳遞的
#調用形式: 對象.方法([實參])
dingding.bark() #等價調用形式:bark(dingding)
注意:
self參數在調用的時候不必傳值,由系統傳值
self隻能在實例方法中使用
方法和函數的差別:
方法作用域屬于類,是以即便和普通函數重名,也不會被覆寫
方法的第一個參數必須是self,但函數不要求
方法必須通過對象調用,而函數不需要
方法的第一個參數self其實可以使任何合法辨別符,不過一般約定俗成都是self
方法的連貫調用
class Dog:
def bark(self):
print("汪汪汪")
return self #傳回self
def eat(self):
print("愛啃大骨頭")
return self
dog = Dog()
dog.eat().bark() #方法的連貫調用,方法要傳回self
2.4 對象的建立
對象的建立過程也稱之為對象的實例化過程,也就是定義了了一個類型的變量或者
稱之為實例(instance)的過程
#文法: 對象 = 類名([實參])
dingding = Dog() #實例化一個對象
print(dingding) #<__main__.Dog object at 0x00000000023F40B8>
print(type(dingding)) #<class '__main__.Dog'>
#檢視對象的類名
print(dingding.__class__)
2.5 成員屬性
成員屬性描述的是對象的靜态特征,比如說狗名字、品種等,其實就是一個變量,
作用域屬于對象,不會和類外的全局變量沖突。python中成員屬性可以在構造函
數中添加。成員屬性屬于對象,每個對象的成員屬性的值都不同
在構造函數中添加的屬性屬于所有對象(重點)
#添加屬性文法:
對象.成員屬性 = 值
#引⽤⽅式:對象.成員屬性
class Dog(object):
def __init__(self,name,kind,age):
self.name = name
self.kind = kind
self.age = age
def bark(tmp):
print('我是小可愛--丁丁')
dingding = Dog('丁丁','泰迪',3)
print('我是可愛的%s⽝犬,%s,我今年%d歲了了' % (dingding.kind,
dingding.name, dingding.age))
#檢視執行個體屬性
print(dingding.__dict__) #__dict__屬性可以用來檢視實例屬性
print(dir(dingding)) #檢視Dog的屬性,包括執行個體屬性
3.封裝
隐藏對象的屬性和實作細節,僅對外公開接口,控制在程式中屬性的讀取和修改的
通路級别。
#文法: 對象 = 類名([實參])
dingding = Dog() #執行個體例化⼀一個對象
print(dingding) #<main.Dog object at 0x00000000023F40B8>
print(type(dingding)) #<class ‘main.Dog’>
#檢視對象的類名
print(dingding.class)
#添加屬性文法:
對象.成員屬性 = 值
#引用方式:對象.成員屬性
class Dog(object):
def init(self,name,kind,age):
self.name = name
self.kind = kind
self.age = age
def bark(tmp):
print(‘我是小可愛–丁丁’)
dingding = Dog(‘丁丁’,‘泰迪’,3)
print(‘我是可愛的%s⽝犬,%s,我今年%d歲了了’ % (dingding.kind,
dingding.name, dingding.age))
#檢視執行個體屬性
print(dingding.dict) #__dict__屬性可以用來檢視實例屬性
print(dir(dingding)) #檢視Dog的屬性,包括執行個體屬性
類本身就是⼀一種封裝,通過類可以将資料(屬性)和行行為(方法)相結合,形成一
個有機的整體,也就是将資料與對資料的操作有機的結合。封裝的目的是增強安全
性和簡化程式設計,使用者不必了了解具體的實作細節,而隻是要通過外部接口,以特定
的通路權限來使用類的成員。成員私有化是實作封裝的手段。所有的成員預設是公
有。
3.1 屬性私有化
如果想讓類的内部屬性不被外界直接通路,可以在這個屬性的前面加兩個下劃線__
,在Python中,如果一個屬性的前面出現 __,就表示這個屬性隻能在目前類的方法中
被直接通路,不能通過對象直接通路,這個變量量就被稱為私有變量
class Dog:
def __init__(self,name,gender,age):
self.name = name
self._gender = gender #'保護'變量
self.__age = age #私有變量
#定義一個公開的方法,間接通路私有變量
def get_age(self):
return self.__age
#定義⼀一個公開方法,間接設定私有變量
def set_age(self,age):
self.__age = age
ding = Dog('丁丁','公',5)
print(ding.name)
# print(ding.__age) #AttributeError: 'Dog' object has no attribute
'__age'
print(ding.get_age()) #5 擷取私有屬性的值
ding.set_age(10) #設定私有屬性的值
print(ding.get_age()) #10
print(ding._gender)
#可以通過 _Dog__age通路私有變量,但不不建議
print(ding._Dog__age)
【⾯面試題】
常見的在變量的前後加下劃線的問題:
單下劃線:_age ----->受保護的 可以通路,當約定俗稱,當你看到一個下劃線開頭
的成員時不應該使⽤用它
雙下劃線:__age ------>私有的
兩邊都雙下劃線:__age__ ------->系統内置變量
3.2 屬性裝飾器器
對于私有屬性的通路,使用公開方法間接通路的方法太麻煩,python提供了一種
便捷文法,屬性裝飾器,通過屬性裝飾器,可以很方便的對私有屬性進通路,屬性
修飾器可以把方法屬性化。
class Dog:
def __init__(self,name,gender,age):
self.name = name
self._gender = gender
self.__age = age
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
self.__age =age
ding = Dog('丁丁','公',5)
print(ding.name)
print(ding.age)
ding.age =10
print(ding.age)
print(ding._gender)
3.3 成員方法私有化
如果一個方法的名字前面加__,聲明該方法為私有方法,隻能在目前類中被調用,
在外界不能通過對象直接調用,這就是私有方法
class Dog:
def __init__(self,name,age):
self.name = name
self.age = age
def __pee(self):
print('這是我的地頭')
dog = Dog('dingding',5)
#dog.__pee() #AttributeError: 'Dog' object has no attribute '__pee'
4 構造和析構
4.1 構造方法
目的:構造方法用于初始化對象(不建立對象),可以在構造方法中添加成員屬
性
時機:實例化對象的時候自動調用
參數:第一個參數必須是self,其它參數根據需要自己定義
傳回值:不傳回值,或者說傳回None,不應該傳回任何其他值
文法:
def __init__(self,arg1,arg2....):
函數體
#參數:arg1,agr2...根據需要自己定義
#如果自己不定義構⽅方法,系統自動生成一個構造函數
def __init__(self):
pass
注意:
如果沒有定義構造方法,系統會生成一個無參構造方法,如果自己定義了構造
方法,則系統不會自動生成
class 類名:
def __init__(self):
pass
``
一個類隻能有一個構造方法,如果定義多個,後面的會覆寫前面的
構造函數由系統在實例化對象時自動調用,不要自己調用
class Dog(object):
def init(self,name,kind,age):
self.name = name #定義對象屬性,這個類所有的對象都具有該屬性
self.kind = kind #成員屬性必須通過self.引⽤用,否則是普通變量
self.age = age
def bark(tmp):
print(‘我是小可愛–丁丁’)
dingding = Dog(‘丁丁’,‘泰迪’,3)
print(‘我是可愛的%s⽝犬,%s,我今年%d歲了了’ % (dingding.kind,
dingding.name, dingding.age))
4.2 析構方法
目的:對象銷毀時,釋放資源
時機:對象銷毀時由系統自動調用
參數:除了self外,沒其他參數
傳回值:不傳回值,或者說傳回None。
文法:
def del(self):
#to do
class Dog(object):
#構造
def init(self,name,kind,age):
self.name = name
self.kind = kind
self.age = age
#析構
def del(self):
print(‘拜拜了,二十年後又是一條好漢’)
def bark(tmp):
print(‘我是小可愛–丁丁’)
dingding = Dog(‘丁丁’,‘泰迪’,3)
print(‘我是可愛的%s犬,%s,我今年%d歲了’ % (dingding.kind,
dingding.name, dingding.age))
del dingding #銷毀對象,自動調用析構方法
#在函數中對象,當函數結束運行時,自動析構
def test():
td = Dog(‘當當’,‘泰迪’,3)
4.3 __str__ __str__
目的:将對象轉化為字元串
時機:凡是涉及對象向字元串轉換的都會調用(print,str)
參數:self
傳回值:字元串
__repr__ 作用同 __str__ 不過是給解釋器看的
class Animal:
def init(self,name,age):
self.name = name
self.__age =age
def str(self):
return “name : {} age : {}”.format(self.name,self.__age)
def repr(self):
return self.str()
a1 = Animal(‘zhu’,3)
print(a1)
print('我是⼀一頭可愛的 ’ + str(a1)