天天看點

python之__del__()魔方方法:銷毀對象,記憶體回收

前言

①python通過調用 __init__() 方法構造目前類的執行個體化對象。【建立對象時,python解釋器預設調用 __init__() 方法】

② __del__() 方法的功能正好與 __init__() 方法相反,其用來銷毀執行個體化對象。【删除一個對象時,python解釋器預設調用 __del__() 方法】

③事實上在編寫程式時,如果之前建立的類執行個體化對象後續不再使用,最好在适當位置手動将其銷毀,釋放其占用的記憶體空間(整個過程稱為垃圾回收(簡稱GC))。

④大多數情況下,Python 開發者不需要手動進行垃圾回收,因為 Python 有自動的垃圾回收機制,能自動将不需要使用的執行個體對象進行銷毀。

執行個體講解

  __del__() :

使用場景:

        1、當删除對象時,Python解析器會預設調用 __del__()  方法,即對象引用執行完後python會自動調用 __del__() 方法。

        2、銷毀(釋放)記憶體中的對象時回調 __del__() 方法。

執行個體一:

class CLanguage:
    def __init__(self):
        print("調用 __init__() 方法構造對象")

    def __del__(self):
        print("調用__del__() 銷毀對象,釋放其空間")


clangs = CLanguage()
del clangs      

運作結果:

python之__del__()魔方方法:銷毀對象,記憶體回收

【注意1】:不能誤認為,隻要該執行個體對象調用 __del__() ,該執行個體對象所占用的記憶體空間就會被釋放。

比如:

class CLanguage:
    def __init__(self):
        print("調用 __init__() 方法構造對象")

    def __del__(self):
        print("調用__del__() 銷毀對象,釋放其空間")


clangs = CLanguage()
# 添加一個引用clangs對象的執行個體對象
cl = clangs
del clangs  # 删除執行個體對象(實際上是對執行個體對象的引用計數減1)
print("***********")      

運作結果:上述代碼最後一行輸出資訊,是程式執行即将結束時調用 __del__() 方法輸出的。

python之__del__()魔方方法:銷毀對象,記憶體回收

 解釋說明:

①當程式中有其它變量(比如上述代碼中的cl變量)引用該執行個體對象時,即便手動調用  __del__()  方法,該方法也不會立即執行。這和 Python 的垃圾回收機制的實作有關。

②Python 采用自動引用計數(簡稱 ARC)的方式實作垃圾回收機制。該方法的核心思想是:每個 Python 對象都會配置一個計數器,初始 Python 執行個體對象的計數器值都為 0,如果有變量引用該執行個體對象,其計數器的值會加 1,依次類推;反之,每當一個變量取消對該執行個體對象的引用,計數器會減 1。如果一個 Python 對象的的計數器值為 0,則表明沒有變量引用該 Python 對象,即證明程式不再需要它,此時 Python 就會自動調用  __del__()  方法将其回收。

③以上面程式中的 clangs 為例,實際上建構 clangs 執行個體對象的過程分為 2 步,先使用 CLanguage() 調用該類中的 __init__() 方法構造出一個該類的對象(将其稱為 C,計數器為 0),并立即用 clangs 這個變量作為所建執行個體對象的引用( C 的計數器值 + 1)。在此基礎上,又有一個 cl變量引用 clangs(其實相當于引用 CLanguage(),此時 C 的計數器再 +1 ),這時如果調用 del clangs 語句,隻會導緻 C 的計數器減 1(值變為 1),因為 C 的計數器值不為 0,是以 C 不會被銷毀(不會執行  __del__()  方法)。

④再次舉例:當執行 del cl 語句時,其應用的對象執行個體對象 C 的計數器繼續 -1(變為 0),對于計數器為 0 的執行個體對象,Python 會自動将其視為垃圾進行回收。

class CLanguage:
    def __init__(self):
        print("調用 __init__() 方法構造對象")

    def __del__(self):
        print("調用__del__() 銷毀對象,釋放其空間")


clangs = CLanguage()
# 添加一個引用clangs對象的執行個體對象
cl = clangs
del clangs  # 删除執行個體對象(實際上是對執行個體對象的引用計數減1)
print("***********")
del cl  # 删除執行個體對象(實際上是對執行個體對象的引用計數再減1)
print("-----------")      

運作結果:

python之__del__()魔方方法:銷毀對象,記憶體回收

執行個體二:

class User:
    def __init__(self, username):
        self.user = username
        print('User 初始化成功---')

    def get_info(self):
        print(self.user)

    def __del__(self):
        print('User 對象被回收---')


if __name__ == '__main__':
    # 建立一個user對象
    u = User(username='XXX')

    # 删除該User對象
    del u

    print('del u -------------')      

運作結果:

python之__del__()魔方方法:銷毀對象,記憶體回收

代碼詳解:

  u = User() 在記憶體中建立了一個 User 對象,并且讓變量 u 引用記憶體中的 User 對象。

  del u 删除變量 u , 此時記憶體中的 User 對象沒有任何變量對其引用,Python解析器就會回調  __del__() 方法,回收記憶體。

執行個體三:

class User:
    def __init__(self, username):
        self.user = username
        print('User 初始化成功---')

    def get_info(self):
        print(self.user)

    def __del__(self):
        print('User 對象被回收---')


if __name__ == '__main__':
    u1 = User('XXX')
    u2 = u1

    del u1
    print('del u1 -------')

    del u2
    print('del u2 -------')      

運作結果:

python之__del__()魔方方法:銷毀對象,記憶體回收

代碼解析:

  u1 = User() 建立一塊存放 User 對象的記憶體,并且,變量 u1 指向該記憶體。

  u2 = u1 此處又建立變量 u2, 并且 u2 引用了 u1 的記憶體位址,此時,u1 和 u2 同時引用同一個記憶體位址。

  del u1 删除 u1 時,删除該變量對User對象的引用,此時,由于記憶體中的 User 對象還在被 u2 引用,是以不會回收該記憶體(不會回調 __del__() 方法)。

  del u2 删除 u2 後,記憶體中的 User 對象已經沒有引用的變量,此時解釋器才會對記憶體進行回收,回調  __del__() 方法。

執行個體四:當執行個體對象的引用計數為0時,python解釋器會自動調用 __del__() 銷毀對象,回收記憶體空間。

class User:
    def __init__(self, username):
        self.user = username
        print('User 初始化成功---')

    def get_info(self):
        print(self.user)

    def __del__(self):
        print('User 對象被回收---')


if __name__ == '__main__':
    User('XXX').get_info()