Python 面向對象:類的創建及其基本內置方法的使用
首先了解一下什麼是面向對象
- 面向過程:
就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。
例如五子棋,面向過程的設計思路就是首先分析問題的步驟:1、開始遊戲,2、黑子先走,3、繪製畫面,4、判斷輸贏,5、輪到白子,6、繪製畫面,7、判斷輸贏,8、返回步驟2,9、輸出最後結果。把上面每個步驟用分別的函數來實現,問題就解決了。- 面向對象
是把構成問題事務分解成各個對象,建立對象的目的不是爲了完成一個步驟,而是爲了描敘某個事物在整個解決問題的步驟中的行爲。
面向對象的設計則是從另外的思路來解決問題。整個五子棋可以分爲 1、黑白雙方,這兩方的行爲是一模一樣的,2、棋盤系統,負責繪製畫面,3、規則系統,負責判定諸如犯規、輸贏等。第一類對象(玩家對象)負責接受用戶輸入,並告知第二類對象(棋盤對象)棋子佈局的變化,棋盤對象接收到了棋子的i變化就要負責在屏幕上面顯示出這種變化,同時利用第三類對象(規則系統)來對棋局進行判定。
1 類的建立及對象的創建
在面向對象編程中,你編寫表示現實世界中的事物和情景的類,並基於這些類來創建對象。編寫類時,你定義一大類對象都有的通用行爲。基於類創建對象 時,每個對象都自動具備這種通用行爲,然後可根據需要賦予每個對象獨特的個性。
- 要設計一個類,通常要滿足三個要求:
- 類名:這類事物的總稱,滿足大駝峯命名法
- 屬性:這類事物所具有的特徵
- 方法:這類事物具有什麼樣的行爲
1.1 簡單的類的定義
定義簡單的類:
class 類名:
def 方法一(self,參數列表):
pass
def 方法二(self,參數列表):
pass
示例:定義一個動物類,動物一般都能吃喝跑睡
class Animal(): # 類名稱
def drunk(self): # 方法
pass
def eat(self): # 方法
pass
def run(self): # 方法
pass
def sleep(self): # 方法
pass
執行如下:
1.2 屬性的添加及調用
類中必定包含此類的特點,也就是所謂的屬性,此時要調用一個內置方法_ init _(self)
借用上一個動物的例子,基本的每個動物都有姓名和年齡,這就是其屬性
示例如下:
class Animal():
def __init__(self,name,age): # 初始化屬性 name 和 age
self.name = name
self.age = age
def drunk(self):
print '%s 要喝水' % self.name
def eat(self):
print '%s 要吃飯' % self.name
def run(self):
print '%s 要跑步' % self.name
def sleep(self):
print '%s 要睡覺' % self.name
cat = Animal('cat',2) # 通過類來創建實例
cat.run() # 調用類中的方法
cat.drunk()
cat.eat()
cat.sleep()
===========================================================================================
其中:
1. def __init__(self,name,age):
self.name = name
self.age = age
兩個變量都有前綴 self 。以 self 爲前綴的變量都可供類中的所有方法使用,我們還可以通過類的任何實例來訪問這
些變量。 self.name = name 獲取存儲在形參 name 中的值,並將其存儲到變量 name 中,然後該變量被關聯到當前
創建的實例。 self.age = age 的作用與此類似。像這樣可通過實例訪問的變量稱爲屬性 。
2. cat = Animal('cat',2)
通過對象名 = 類名(實參) 的形式來創建實例,類在進行實例化之前系統是不會給其分配內存空間的
3. cat.run()
類中方法的調用,是通過 實例.方法名稱 進行調用的
執行如下:
控制檯顯示如下:
2. 方法
類中的函數稱爲方法 ;你前面學到的有關函數的一切都適用於方法,就目前而言,唯一重要的差別是調用方法的方式。
上面對類的建立中使用了一個基本的內置方法 _ init _(self),下面就介紹一下幾種常用的內置方法
2.1 _ init _ ()初始化方法
- 當使用類名( )創建對象時,python的解釋器會自動執行以下操作
- 爲對象在內存中分配空間–創建對象
- 調用初始化方法爲對象的屬性設置初始值–初始化方法(_ init ),這個初始化方法就是: init _ 方法, _ init _ 是對象的內置方法, _ init _ 方法時專門用來定義一個類具有哪些屬性的方法
示例:定義一個動物類,動物一般都有名稱年齡
class Animal(): # 定義一個類
def __init__(self,name,age):
# 初始化方法來進行屬性添加
self.name = name
self.age = age
def attr(self):
# 定義此方法,返回屬性的值
return self.name,self.age
cat = Animal('cat',2) # 建立實例
print cat.attr() # 調用實例方法來進行顯示返回屬性的值
執行如下:
控制檯結果如下:
2.2 _ del _()方法
當刪除一個對象時,python解釋器會默認調用一個方法,這個方法爲_ del _ ()方法。在python中,對於開發者來說很少會直接銷燬對象(如果需要,應該使用del關鍵字銷燬)。Python的內存管理機制能夠很好的勝任這份工作。也就是說,不管是手動調用 del 還是由 python自動回收都會觸發 _ del _ 方法執行:
示例:
class Animal(object):
# 初始化方法
# 創建完對象後會自動被調用
def __init__(self, name):
print('__init__方法被調用')
self.name = name
# 析構方法
# 當對象被刪除時,會自動被調用
def __del__(self):
print("__del__方法被調用")
print("%s對象馬上被幹掉了..." % self.name)
# 創建對象
dog = Animal("哈皮狗")
# 刪除對象,__del__ 方法被調用
del dog
cat = Animal("波斯貓")
print '馬上刪除%s',cat.name
# 若不主動刪除對象,會先執行此命令,再調用__del__命令
執行如下:
控制檯顯示如下:
2.3 _ str _()方法
在 python 中,使用 python 輸出對象變量,
默認情況下,會輸出這個變量引用的對象是由哪一個類創建的以及在內存中的地址(十六進制表示)
如果在開發中,希望使用print輸出對象變量時,
能夠打印自定義的內容,就可以利用_ str 這個內置方法了
需要通過 return 來返回所要輸出的字符串
示例:不使用 _ str _ 方法之前
class Animal():
# 初始化方法
# 創建完對象後會自動被調用
def __init__(self, name):
print('__init__方法被調用')
self.name = name
# 建立對象
cat = Animal('Tom')
print cat # 直接顯示實例,返回的是實例指向的內存地址
執行如下:
控制檯顯示如下:
示例:使用 _ str _ 方法之後
class Animal():
# 初始化方法
# 創建完對象後會自動被調用
def __init__(self, name):
print('__init__方法被調用')
self.name = name
def __str__(self):
return '返回 %s' % self.name
cat = Animal('Tom')
print cat
執行如下:
控制檯顯示:
2.4 _ new _()方法(單例)
在進行 _ new _ 方法的介紹之前先介紹一個概念:新式類與舊式類
- Python中類分兩種:舊式類和新式類:
新式類,舊式類(經典類)
新式類 定義時給類後加上(object)
class A(object)
pass
python 3 以後若是未指定繼承自object 會默認繼承自 object 類
python 3 以前則不會,需要進行指定
可通過 dir()函數,來查看對象可調用的類的方法
示例:新式類
class A(object):
pass
a = A()
# 通過print來查看
print dir(a)
舊式類示例:
class B:
pass
b = B()
print dir(b)
執行如下:
控制檯顯示如下:
注:
新式類舊式類最明顯的區別在於繼承搜索的順序發生了改變
即:
經典類多繼承搜索順序(深度優先):
先深入繼承樹左側查找,然後再返回,開始查找右側
新式類多繼承搜索順序(廣度優先):
先在水平方向查找,然後再向上查找。
此種區別會在面向對象特點——繼承中介紹到
下面介紹 _ new _ 方法
_ new _ ()是在新式類中新出現的方法,它作用在構造方法建造實例之前,可以這麼理解,在Python 中 存在於類裏面的構造方法 _ init _ () 負責將類的實例化,而在 _ init _ ()啓動之前, _ new _ ()決定是否 要使用該 _ init _ ()方法,因爲_ new _ ()可以調用其他類的構造方法或者直接返回別的對象來作爲本類 的實例。
如果將類比喻爲工廠,那麼_ init _ ()方法則是該工廠的生產工人,_ init _ ()方法接受的初始化參數則是生產所需原料,_ init _ ()方法會按照方法中的語句負責將原料加工成實例以供工廠出貨。而 _ new _ ()則是生產部經理,_ new _ ()方法可以決定是否將原料提供給該生產部工人,同時它還決定着出貨產品是否爲該生產部的產品,因爲這名經理可以借該工廠的名義向客戶出售完全不是該工廠的產品。
_ new _ ()方法的特性:
_ new _ ()方法是在類準備將自身實例化時調用。
_ new _ ()方法始終都是類的靜態方法,即使沒有被加上靜態方法裝飾器。
靜態方法在下面會講到
_ new _ () 最經典的作用,實現單例
單例:單例模式,是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個實例。即一個類只有一個對象實例
示例:
class MusicPlayer(object):
instance = None
def __new__(cls, *args, **kwargs):
# 第一個參數cls:哪一類調用,就傳遞哪一類
# 第二個參數 *args:多值參數
# 第三個參數 **kwargs:多值的字典參數
# 創建對象的時候,new方法會被自動調用
# 重寫了父類的方法
if cls.instance is None:
cls.instance = object.__new__(cls)
return cls.instance
player1 = MusicPlayer()
print player1
player2 = MusicPlayer()
print player2
執行如下:
控制檯顯示如下:
由控制檯顯示可知,實例 player1 player2所返回的內存地址相同,故爲本質上爲同一實例
3 幾種特殊屬性及方法(類屬性,類方法,靜態方法,私有屬性,私有方法)
3.1 私有屬性,私有方法
如果一個屬性是以兩個下劃線開始 就標識這個這個屬性是一個私有屬性
如果一個自定義方法是以兩個下劃線開始 就標識這個這個方法是一個私有方法
私有屬性私有方法都不能直接訪問
示例:私有屬性
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定義私有屬性
cat = Animal('cat',2)
print cat.name
print cat.__age
# 在外部調用私有屬性會顯示該類沒有此屬性
執行如下:
控制檯顯示如下:
可在類的內部調用私有屬性:
執行如下:
控制檯顯示如下:
示例:私有方法
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定義私有屬性
def __test(self): # 定義私有方法
print '這是私有方法'
cat = Animal('cat', 2)
cat.__test() # 在外對私有方法進行調用
執行如下:
控制檯顯示如下:
想要對私有方法進行調用,可以在類中定義公有方法,通過公有方法間接調用私有方法
示例:
class Animal(object):
def __init__(self, name, age):
self.name = name
self.__age = age # 定義私有屬性
def __test(self): # 定義私有方法
print '這是私有方法'
def test(self):
print '這是公有方法,通過此方法調用私有方法'
Animal.__test(self)
cat = Animal('cat', 2)
cat.test()
執行如下:
控制檯顯示如下:
3.2 類屬性,類方法
- 類是一個特殊的對象
Python中一切皆對象
class AAA: 定義的類屬性屬於類對象
obj1 = AAA:屬於實例對象
在運行程序時,類 同樣會被加載到內存
類對象可以有自己屬性和方法
通過 類名. 的方式可以直接訪問類的屬性或者調用類的方法
3.2.1 類屬性
- 類屬性是針對類對象定義的屬性
使用複製語句在class關鍵字下方可以定義類屬性
類屬性用於記錄這個類相關的特性
示例:
class Tool():
count = 0
# 使用賦值語句定義類的屬性,記錄所有的工具的數量
def __init__(self,name):
self.name = name
Tool.count += 1
# 讓類的屬性加1
# 創建工具對象(對象在創建的時候,會自動調用初始化方法)
tool1 = Tool('鋤頭')
tool2 = Tool('斧頭')
# 輸出工具對象的總數
# 使用 ‘類名.屬性名’ 來獲取
print Tool.count
執行如下:
控制檯顯示如下:
3.2.2 類方法
- 類方法就是針對類對象定義的方法
在類方法內部就可以直接訪問類屬性或者調用其他類方法- 語法如下:
@classmethod
def 類方法(cls)
pass
示例:
class Car(object):
# 定義類屬性
count = 0
@classmethod
def show_car_count(cls):
# cls.count:在類方法內部訪問類屬性
print '汽車對象的數量爲 %s' % cls.count
def __init__(self,name):
self.name = name
Car.count += 1
# 創建car對象
car1 = Car('Bwm')
car2 = Car('Benci')
car3 = Car('Toyota')
# 調用類方法
Car.show_car_count()
執行如下:
控制檯顯示如下:
3.2.3 靜態方法
靜態方法
- 靜態方法
在開發時,如果需要在類中封裝一個方法,這個方法:
即不需要訪問實例屬性或者調用實例方法
也不需要訪問類屬性或者調用類方法
這時可以把這個方法封裝成一個靜態方法- 語法如下:
@staticmethod
def 靜態方法():
pass
示例:
class Car(object):
@staticmethod
def tool():
# 靜態方法不需要傳遞第一個參數:self
print 'By car to school is too convinent!'
# 通過類名,調用靜態方法
# 不需要創建對象,直接可以調用
Car.tool()
執行如下:
控制檯顯示如下:
4. 以上幾種的對比
4.1 類對象和實例對象的區別
類對象就是類本身,當遇見類的時候,就會創建新的命名空間,命名空間
包含所有類變量和方法定義的名稱。
實例對象就是通過類對象創建出來的實例(類對象實例化之後返回的
就是實例對象),用來存儲實例屬性和存儲實例對象的引用。
4.2 類屬性和實例屬性的區別
類屬性:定義在類內部,方法外邊,屬於所有類對象和所有實例對象
調用:類對象.屬性 = 值
實例屬性:通過init初始化的變量和實例對象創建出來的屬性
調用:實例對象.屬性
4.3 類方法和實例方法和靜態方法的區別
類方法:必須有一個參數,這個參數表示爲當前類對象,一般爲cls,在
方法的頭部加上@classmethod
實例方法:必須有一個參數,表示當前實例對象,一般是self
靜態方法:普通函數的格式,不需要強制要求傳遞參數,在方法的頭部
加上註釋@staticmethod一般用於實例對象、類對象無關的