Python 類
Python中的類提供了面向對象編程的所有基本功能:類的繼承機制允許多個基類,派生類可以覆蓋基類中的任何方法,方法中可以調用基類中的同名方法。
對象可以包含任意數量和類型的數據。
python類與c++類相似,提供了類的封裝,繼承、多繼承,構造函數、析構函數。
在python3中,所有類最頂層父類都是object類,與java類似,如果定義類的時候沒有寫出父類,則object類就是其直接父類。
類定義
類定義語法格式如下:
class ClassName: <statement-1> . . . <statement-N>
類對象:創建一個類之后,可以通過類名訪問、改變其屬性、方法
實例對象:類實例化后,可以使用其屬性,可以動態的為實例對象添加屬性(類似javascript)而不影響類對象。
類的屬性
可以使用點(.)來訪問對象的屬性
也可以使用以下函數的方式來訪問屬性:
-
getattr(obj, name[, default]) : 訪問對象的屬性
-
hasattr(obj,name) : 檢查是否存在一個屬性
- setattr(obj,name,value) : 設置一個屬性。如果屬性不存在,會創建一個新屬性
- delattr(obj, name) : 刪除屬性
Python內置類屬性
-
__dict__ : 類的屬性(包含一個字典,由類的數據屬性組成)
-
__doc__ :類的文檔字符串
-
__name__: 類名
-
__module__: 類定義所在的模塊(類的全名是'__main__.className',如果類位於一個導入模塊mymod中,那么className.__module__ 等於 mymod)
-
__bases__ : 類的所有父類構成元素(包含了以個由所有父類組成的元組)
1 class Person: 2 "Person類" 3 def __init__(self, name, age, gender): 4 print('進入Person的初始化') 5 self.name = name 6 self.age = age 7 self.gender = gender 8 print('離開Person的初始化') 9 10 def getName(self): 11 print(self.name) 12 13 p = Person('ice', 18, '男') 14 15 print(p.name) # ice 16 print(p.age) # 18 17 print(p.gender) # 男 18 print(hasattr(p, 'weight')) # False 19 # 為p添加weight屬性 20 p.weight = '70kg' 21 print(hasattr(p, 'weight')) # True 22 print(getattr(p, 'name')) # ice 23 24 print(p.__dict__) # {'age': 18, 'gender': '男', 'name': 'ice'} 25 print(Person.__name__) # Person 26 print(Person.__doc__) # Person類 27 print(Person.__dict__) # {'__doc__': 'Person類', '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__init__': <function Person.__init__ at 0x000000000284E950>, 'getName': <function Person.getName at 0x000000000284EA60>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__module__': '__main__'} 28 print(Person.__mro__) # (<class '__main__.Person'>, <class 'object'>) 29 print(Person.__bases__) # (<class 'object'>,) 30 print(Person.__module__) # __main__
類的方法
在類地內部,使用def關鍵字可以為類定義一個方法,與一般函數定義不同,類方法必須包含參數self,且為第一個參數。
類的專有方法:
-
__init__ 構造函數,在生成對象時調用
-
__del__ 析構函數,釋放對象時使用
-
__repr__ 打印,轉換
-
__setitem__按照索引賦值
-
__getitem__按照索引獲取值
-
__len__獲得長度
-
__cmp__比較運算
-
__call__函數調用
-
__add__加運算
-
__sub__減運算
-
__mul__乘運算
-
__div__除運算
-
__mod__求余運算
-
__pow__稱方
__init__()方法是一種特殊的方法,被稱為類的構造函數或初始化方法,當創建了這個類的實例時就會調用該方法,與c++中構造函數類似。只需在自定義的類中重寫__init__()方法即可。
1 class Person: 2 def __init__(self, name, age, gender): 3 print('進入Person的初始化') 4 self.name = name 5 self.age = age 6 self.gender = gender 7 print('離開Person的初始化') 8 9 def getName(self): 10 print(self.name) 11 12 # Person實例對象 13 p = Person('ice', 18, '男') 14 print(p.name) 15 print(p.age) 16 print(p.gender) 17 p.getName() 18 19 # 進入Person的初始化 20 # 離開Person的初始化 21 # ice 22 # 18 23 # 男 24 # ice
析構函數 __del__ ,__del__在對象消逝的時候被調用,當對象不再被使用時,__del__方法運行:
類的封裝
python通過變量名命名來區分屬性和方法的訪問權限,默認權限相當於c++和java中的public
類的私有屬性: __private_attrs:兩個下划線開頭,聲明該屬性為私有,不能在類地外部被使用或直接訪問。在類內部的方法中使用時self.__private_attrs。
類的私有方法:__private_method:兩個下划線開頭,聲明該方法為私有方法,不能在類地外部調用。在類的內部調用 self.__private_methods
雖然python不允許實例化的類訪問私有數據,但可以使用 object._className__attrName 訪問屬性。其實python內部私有化的實現只是將attrName屬性變為了_className__attrName而已
1 class Demo: 2 __id = 123456 3 4 def getId(self): 5 return self.__id 6 7 temp = Demo() 8 # print(temp.__id) # 報錯 AttributeError: 'Demo' object has no attribute '__id' 9 print(temp.getId()) # 123456 10 print(temp._Demo__id) # 123456
類的繼承
面向對象的編程帶來的主要好處之一是代碼的重用,實現這種重用的方法之一是通過繼承機制。繼承完全可以理解成類之間的類型和子類型關系。
需要注意的地方:繼承語法 class 派生類名(基類名)://... 基類名寫作括號里,基本類是在類定義的時候,在元組之中指明的。
在python中繼承中的一些特點:
- 1:在繼承中基類的構造(__init__()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。使用super().__init__()或parentClassName.__init__()
- 2:在調用基類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別於在類中調用普通函數時並不需要帶上self參數
- 3:Python總是首先查找對應類型的方法,如果它不能在派生類中找到對應的方法,它才開始到基類中逐個查找。(先在本類中查找調用的方法,找不到才去基類中找)。
如果在繼承元組中列了一個以上的類,那么它就被稱作"多重繼承" 。
語法:
派生類的聲明,與他們的父類類似,繼承的基類列表跟在類名之后,如下所示:
多態
如果父類方法的功能不能滿足需求,可以在子類重寫父類的方法。實例對象調用方法時會調用其對應子類的重寫后的方法