Python類方法__init__和__del__構造、析構過程分析

來源:互聯網
上載者:User
最近學習《Python參考手冊》學到Class部分,遇到了類的構造析構部分的問題:

1、什麼時候構造?
2、什麼時候析構?
3、成員變數如何處理?
4、Python中的共用成員函數如何訪問?
------------------------
探索過程:
1、經過尋找,Python中沒有專用的構造和解構函式,但是一般可以在__init__和__del__分別完成初始化和刪除操作,可用這個替代構造和析構。還有一個__new__用來定製類的建立過程,不過需要一定的配置,此處不做討論。
2、類的成員函數預設都相當於是public的,但是預設開頭為__的為私人變數,雖然是私人,但是我們還可以通過一定的手段訪問到,即Python不存在真正的私人變數。如:

代碼如下:


__priValue = 0 # 會自動變形為"_類名__priValue"的成員變數

3、由於Python的特殊性,全域成員變數是共用的,所以類的執行個體不會為它專門分配內容空間,類似於static,具體使用參看下面的例子。

測試1:

代碼如下:


# encoding:utf8

class NewClass(object):
num_count = 0 # 所有的執行個體都共用此變數,即不單獨為每個執行個體分配
def __init__(self,name):
self.name = name
NewClass.num_count += 1
print name,NewClass.num_count
def __del__(self):
NewClass.num_count -= 1
print "Del",self.name,NewClass.num_count
def test():
print "aa"

aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa")

print "Over"

調試運行:

代碼如下:


Hello 1
World 2
aaaa 3
Over
DeException l Hello 2
AttributeError: "'NoneType' object has no attribute 'num_count'" in > ignored
Exception AttributeError: "'NoneType' object has no attribute 'num_count'" in > ignored


我們發現,num_count 是全域的,當每建立一個執行個體,__init__()被調用,num_count 的值增一,當程式結束後,所有的執行個體會被析構,即調用__del__() 但是此時引發了異常。查看異常為 “NoneType” 即 析構時NewClass 已經被記憶體回收,所以會產生這樣的異常。

但是,疑問來了?為什麼會這樣?按照C/C++等語言的經驗,不應該這樣啊!經過尋找資料,發現:

Python的記憶體回收過程與常用語言的不一樣,Python按照字典順序進行記憶體回收,而不是按照建立順序進行。所以當系統進行回收資源時,會按照類名A-Za-z的順序,依次進行,我們無法掌控這裡的流程。

明白這些,我們做如下嘗試:

代碼如下:


# encoding:utf8

class NewClass(object):
num_count = 0 # 所有的執行個體都共用此變數,即不單獨為每個執行個體分配
def __init__(self,name):
self.name = name
NewClass.num_count += 1
print name,NewClass.num_count
def __del__(self):
NewClass.num_count -= 1
print "Del",self.name,NewClass.num_count
def test():
print "aa"

aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa")

del aa
del bb
del cc

print "Over"

調試輸出:

代碼如下:


Hello 1
World 2
aaaa 3
Del Hello 2
Del World 1
Del aaaa 0
Over

OK,一切按照我們預料的順序發生。
但是,我們總不能每次都手動回收吧?這麼做Python自己的記憶體回收還有什麼意義?

SO,繼續尋找,我們還可以通過self.__class__訪問到類本身,然後再訪問自身的共用成員變數,即 self.__class__.num_count , 將類中的NewClass.num_count替換為self.__class__.num_count 編譯運行,如下:

代碼如下:


# encoding:utf8

class NewClass(object):
num_count = 0 # 所有的執行個體都共用此變數,即不單獨為每個執行個體分配
def __init__(self,name):
self.name = name
self.__class__.num_count += 1
print name,NewClass.num_count
def __del__(self):
self.__class__.num_count -= 1
print "Del",self.name,self.__class__.num_count
def test():
print "aa"

aa = NewClass("Hello")
bb = NewClass("World")
cc = NewClass("aaaa")

print "Over"

結果:

代碼如下:


Hello 1
World 2
aaaa 3
Over
Del Hello 2
Del World 1
Del aaaa 0

Perfect!我們完美地處理了這個問題!

PS:

書上又提到了一些問題,在這裡作補充(僅作為參考):

__new__()是唯一在執行個體建立之前執行的方法,一般用在定義元類時使用。

del xxx 不會主動調用__del__方法,只有引用計數==0時,__del__()才會被執行,並且定義了__del_()的執行個體無法被Python的迴圈垃圾收集器收集,所以盡量不要自訂__del__()。一般情況下,__del__() 不會破壞垃圾處理器。

實驗中發現記憶體回收自動調用了__del__, 這與書上所說又不符,不知是什麼原因,需要繼續學習。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.