Python面向對象里常見的內置成員介紹
好嘞,今天我們繼續剖析下Python里的類。
先前我們定義類的時候,使用到了構造函數,在Python里的構造函數書寫比較特殊,他是一個特殊的函數__init__,其實在類里,除了構造函數還有很多其他格式為__XXX__的函數,另外也有一些__xx__的屬性。下面我們一一說下:
構造函數

Python里所有類的構造函數都是__init__,其中根據我們的需求,構造函數又分為有參構造函數和無慘構造函數。如果當前沒有定義構造函數,那么系統會自動生成一個無參空的構造函數。例如:

在有繼承關系的類中,只要父類被顯示定義,那么子類在創建的時候就會調用父類的構造方法創建父類對象,盡管子類沒有從父類繼承屬性,也會自動被執行。例如:

如果子類想從父類繼承獲取屬性,那么需要顯示調用父類的構造函數才能獲取,否則只能獲取父類方法。例如:

這里我們需要引入一個新的概念,即函數重載。在類內部,如果存在多個函數名相同,函數參數不同(個數不同、類型不同、順序不同)那么我們稱這幾個函數是重載函數,函數返回值不作為重載的依據。在java和C++里我們都有類似的概念。但是Python是動態編程語言,其數據沒有數據類型,因此在類內部我們沒法進行函數重載,因此類內部不能有同名的多個方法,所以我們的構造方法要么不寫,要么只能寫一個。如果不寫系統會自動生成一個空的無參構造方法;如果寫了,那么只能調用該構造方法。另外我們在學習裝飾器的時候似乎在類內部寫了幾個同名的方法,例如:

那么這幾個同名方法是重載關系嗎?不是的,因為他們不是完整的方法,他們一定更要加上@property、@name.setter、@name.deleter限制才是完整的,因此這里不是函數重載。
析構函數
構造函數是在對象創建的時候被自動執行的,其主要職責是對對象進行初始化。析構函數則是在對象銷毀(執行del或被回收)的時候被自動執行的,其主要職責是對對象進行回收。先前我們沒有寫析構方法,那么系統會自動生成一個空的析構函數。接下來我們就寫一個析構函數。Python里的析構方法名為 __del__。例如:

我們這么調用:

執行為

在這里我們要重點說下python的垃圾回收機制。
現在程序員對系統的垃圾回收機制不是特別關注,因為現在硬件發展的很快,我們可用的資源很豐富,服務器內存4G都是小的,可能大多是8G起步,不夠再加。但是對于一些高端崗位和高精行業,垃圾回收機制還是很重要的。所以我們在這里梳理下python里的垃圾回收機制。
Python里的垃圾回收機制以引用計數為主。系統會為每個對象分配一個引用計數器,用來記錄當前對象被使用的次數。既然涉及到計數,就有加和減的操作。系統規定,滿足下述條件進行計數器加1操作:
1.新創建一個對象
2.引用一個對象
3.對象作為實參傳遞。
滿足下述條件進行計數器減1操作:
1.對該對象進行del操作
2.該對象的引用被賦新值
3.對象退出當前作用域(最常見的就是退出函數作用域)
在python里,我們通過sys.getrefcount(對象名),來獲取該對象的當前引用計數器,注意,首次這里的引用計數不一定為1,因為有系統臨時引用。只有當指向對象的引用計數器變成0(首次的初始值)的時候,該對象才會真的被銷毀,該對象的析構函數才會被執行。例如:

輸出為

注意,上述首次調用sys.getrefcount(ad)的時候的返回值為4 說明當前系統有其他的臨時用用,那么我們最終只要到4了說明就返回初始狀態了。最后del ad的時候會將系統臨時引用也釋放。我們當前的運行環境是win+pycharm。我們再改下代碼:

輸出為

從上述輸出可以看出,系統對基本數據類型似乎還有其他操作,造成其初始引用計數比我們預期的引用計數大。而引用數據類型數據則是完全在我們預期的。
只有最終釋放該對象的時候(引用計數為0的時候),__del__析構方法才會被執行。
__str__方法
先看我們的代碼:

輸出為

我們打印該對象的時候,得到是該對象的內存地址,能不能像打印基本數據類型的數據一樣來打印我們的引用數據類型呢?比如說上述類Student應該打印他的實例變量啊。
我們現在提到的__str__方法就是要完成這個功能的,__str__方法有一個返回值,這個返回值就是我們執行print的時候的輸出值,因此我們可以在__str__方法內格式化輸出內容。例如:

輸出為

從上面的輸出可以看出,我們想輸出格式化引用數據類型數據的時候,就要重寫該類里的__str__方法,該方法里你可以設置當前內容的輸出內容。這個__str__方法是object類的方法,因為python里所有類都是直接或者間接從object派生出來的,因此每個引用數據類型都有__str__方法。我們只需要重寫該方法覆蓋父類的方法即可。否則系統會默認去調用object里的__str__方法。
__dict__
可能有些人說了,我怎么知道我的類有哪些內置成員(屬性和方法)呢?比如說上面的__str_我壓根就不知道有這個方法,我怎么調用?python類里確實有個屬性,可以打印出該類的所有內置內容。即__dict__。注意這個__dict__是屬性不是方法,調用的時候不要加()

輸出為

為何stu1.__dict__的輸出內容較少,而Student.__dict__的輸出內容較多呢?因為stu1是對象,對于對象來講,有意義的就是屬性,因為方法是所有對象共享的。而數據是自己特有的,執行的時候只需要攜帶當前的對象的地址就可以執行該類的方法(即self)。而Student是一個類,類是有屬性和方法組成的,所以Student.__dict__的輸出稍微多點,包括方法和屬性。
如果你想知道該類的父類有哪些內置成員,你就打印該類的父類的__dict__屬性即可。例如我們看下Student類的父類object有哪些內置成員,如下:

Ojbect.__dict__的輸出稍微長些,自己打印看下吧,里面肯定有__str__的說明的。
好了,今天我們接觸到了__init__構造函數、__del__析構函數、__str__內置函數、__dict__屬性等,明天我們繼續剖析面向對象里的其他的內置成員。