提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助文檔
@Python類和對象
本文是針對Python類和對象的基礎知識總結。
面向對象編程是在面向過程編程的基礎上發展而來的,它比面向過程編程具有更強的靈活性和擴展性。
面向對象編程(Object-oriented Programming,簡稱OOP),是一種封裝代碼的方法。
面向對象,常用術語包括:
類的創建過程如下:
class 類名:
定義多個類屬性...
定義多個類方法...
先不具體到參數等細節,類屬性和類方法可以實現分化,其中類屬性可以分為類屬性,實例屬性,類方法可以分為實例方法、靜態方法和類方法
無論是類屬性還是類方法,都無法像普通變量或者函數那樣,在類的外部直接使用它們。我們可以將類看做一個獨立的空間,則類屬性其實就是在類體中定義的變量,類方法是在類體中定義的函數。
在類中,根據變量定義的位置不同,以及定義的方式不同,類屬性可以細分為類屬性、實例屬性和局部變量。
類屬性、實例屬性和局部變量三者各有什麼特點?
和類屬性一樣,類方法也可以進行更細致的劃分,具體可分為類方法、實例方法和靜態方法。
Python中區分這3中類方法是采用修飾器進行區分。@classmethod修飾的方法為類方法;采用@staticmethod修飾的方法為靜態方法;不用任何修飾的方法為實例方法。
@classmethod和@staticmethod都是函數修飾器
類方法、靜態方法和實例方法的特點
在定義類的過程中,無論是顯示創建類的構造方法,還是向類中添加實例方法,都要求將self參數作為方法的第一個參數。
那麼,self究竟扮演著什麼樣的角色呢?
事實上,Python只是規定,無論是構造方法還是實例方法,最少要包含一個參數,並沒有規定該參數的具體名稱。之所以將其命名為self,只是程序員之間約定俗成的一種習慣。
self參數的具體作用相當於C++中的this指針。同一個類可以產生多個對象,當某個對象調用類方法時,該對象會把自身的引用作為第一個參數自動傳給該方法,換句話說,Python會自動綁定類方法的第一個參數指向調用該方法的對象。如此,Python解釋器就能知道到底要操作哪個對象的方法了。
因此,程序在調用實例方法和構造方法時,不需要手動為第一個參數傳值。
類的調用方法就是兩種:用類名進行調用和用類的實例對象進行調用。我們對於調用實例方法基本只需要注意一個點。用類的實例對象訪問類成員的方式稱為綁定方法,而用類名調用類成員的方式為非綁定方法。因為類名調用的時候需要手動輸入self參數進行綁定。
Python中,通過使用描述符,可以讓程序員在引用一個對象屬性時自定義要完成的工作。
從本質上看,描述符就是一個類,只不過它定義了另一個類中屬性的訪問方式。像@clsssmethod和@staticmethod就是描述符類的類實例。一個類可以將屬性管理全權委托給描述符類。
描述符是Python中復雜屬性訪問的基礎,它在內部被用於實現property、方法、類方法、靜態方法和super類型。
描述符類基於以下3個特殊方法,換句話說,這3個方法組成了描述符協議:
其中,實現了setter和getter方法的描述符類被稱為數據描述符;如果只實現了getter方法,則稱為非數據描述符。
我們可以將setter方法視為寫函數,當我們添加一個新變量的時候會調用setter函數;將getter方法視為讀函數,當我們通過 類實例名.類變量 等方式讀取類變量時了,用getter函數。
大多數面向對象編程語言都具備3個典型特征,即封裝、繼承和多態。簡單的理解封裝,即在設計類時,刻意地將一些屬性隱藏在類的內部,這樣在使用此類時,將無法直接以“類對象.屬性名”的形式調用這些屬性(或方法 ),而只能用未隱藏的類方法簡介操作這些隱藏的屬性和方法。
類為什麼要封裝呢?
首先,封裝機制保證了類內部數據結構的完整性,因為使用類的用戶無法直接看到類中的數據結構,只能使用類允許公開的數據,很好地避免了外部對內部數據的影響,提高了程序的可維護性。
其次,對一個類實現良好的封裝,用戶只能借助暴露出來的類方法來訪問數據,我們可以避免用戶對類中屬性或方法的不合理操作。
最後,對類進行良好的封裝,還可以提高代碼的復用性。
類如何進行封裝?
Python類中的變量和函數,不是公有的(public),就是私有的(private),這兩種屬性的區別如下:
Python實現類的封裝采用如下方法:
默認情況下,Python類中的變量和方法都是公有的,它們
的名稱前沒有下劃線_
如果類中的變量和函數,名稱以雙下劃線__開頭,那麼它
就變成了私有變量和私有函數
繼承機制經常用於創建和現有類功能類似的新類,又或是新類只需要在現有類基礎上添加一些成員(屬性和方法),但又不想直接將現有類代碼復制給新類。也就是說,通過使用繼承這種機制,可以輕松實現類的重復使用。
Python中,實現繼承的類稱為子類,被繼承的類稱為父類(也可稱為基類、超類)。
子類繼承父類時的語法如下:
class 類名(父類1,父類2,...):
#類定義部分
如果該類沒有顯式指定繼承自哪個類,則默認繼承Object類。另外,Python的繼承是多繼承機制,即一個子類可以同時擁有多個直接父類。
使用多繼承經常需要面對一些問題:多個父類中包含同名的類方法。對於這種情況,Python的處理措施是:根據子類繼承多個父類時這些父類的前後次序決定,即排在前面的父類中的類方法會覆蓋後面父類的同名類方法。
super函數:調用父類的構造方法
Python中子類會繼承父類所有的類屬性和類方法。嚴格來說,類的構造方法其實就是實例方法,因此毫無疑問,父類的構造方法,子類同樣會繼承。
但我們知道,Python是一門支持多繼承的面向對象編程語言,如果子類繼承的多個父類中包含同名的類實例方法,則子類對象在調用該方法時,會優先選擇排在最前面的父類中的實例方法。顯然,構造方法也是如此。
在子類中的構造方法中,調用父類構造方法的方式有兩種,分別是:
1.類可以看做一個獨立空間,在類的外部調用其中的實例方法,可以向調用普通函數那樣,只不過需要額外備注類名(此方式又稱為未綁定方法)
2.使用super()函數。但如果涉及多繼承,該函數只能調用第一個直接父類的構造方法。
涉及到多繼承的時候,在子類構造函數中,調用第一個父類構造方法的方式有以上2種,而調研其他父類構造方法的方式只能使用為綁定方法。
Python是弱類型語言,其最明顯的特征是在使用變量時,無需為其指定具體的數據類型。這會導致一種情況,即同一變量可能會被先後賦值不同的類對象。
類的多態特性需要滿足以下3個前提條件:
1.同一變量被先後賦值不同的類對象。
2.繼承:多態一定是發生在子類和父類之間;
3.重寫:子類重寫了父類的方法。
暫且寫到這兒吧,其他細節日後再補。奧利給