程式設計師必備介面測試偵錯工具:
【相關推薦:Python3視訊教學 】
Python 中的 __del__ 魔法方法,也被稱為物件的終結者,是一個在物件即將被從記憶體中移除之前被呼叫的方法。它實際上並不做從記憶體中刪除物件的工作,我們將在後面看到它是如何發生的。相反,這個方法是用來做任何在物件被移除前需要發生的清理工作。例如,關閉物件在建立時開啟的任何檔案。
在本節中,我們將使用下面這個類作為例子。
class MyNameClass:
def __init__(self, name):
self.name = name
def __del__(self):
print(f"Deleting {self.name}!")
登入後複製
在上面的例子中,我們已經定義了我們的類在初始化時接受一個名字的輸入,當呼叫 finaliser 時,它會通過列印相關範例的名字讓我們知道。這樣,我們就可以瞭解到哪些物件被從記憶體中刪除,以及何時被刪除。
那麼,CPython 什麼時候會決定從記憶體中刪除一個物件呢?有兩種方式(從CPython 3.10 開始)會發生這種情況:參照計數和垃圾回收。
如果我們在 Python 中有一個指向某個物件的指標,那就是對該物件的參照。對於一個給定的物件 a ,CPython 會跟蹤有多少其他東西指向 a 。如果這個計數器達到零,就可以安全地從記憶體中刪除這個物件,因為沒有其他東西在使用它。讓我們看一個例子。
>>> Harward = MyNameClass("Harward")
>>> del Harward
Deleting Harward!
>>>
登入後複製
在這裡,我們建立了一個新的物件(MyNamedClass("Harward")),並建立了一個指向它的指標(Harward =)。然後,當我們刪除 Harwade 時,我們刪除了這個參照,MyNamedClass 範例現在的參照計數為 0。 所以,CPython 決定從記憶體中刪除它--而且,就在這之前,它的 __del__ 方法被呼叫,列印出了我們看到的上面的資訊。
如果我們對一個物件建立了多個參照,我們將不得不擺脫所有的參照,以便使該物件被刪除。
>>> bob = MyNameClass("Bob")
>>> bob_two = bob # creating a new pointer to the same object
>>> del bob # this doesn't cause the object to be removed...
>>> del bob_two # ... but this does
Deleting Bob!
登入後複製
當然,我們的 MyNamedClass 範例本身可以包含指標--畢竟它們是任意的 Python 物件,我們可以給它們新增任何我們喜歡的屬性。讓我們看一個例子。
>>> jane = MyNamedClass("Jane")
>>> bob = MyNamedClass("Bob")
>>> jane.friend = bob # now the "Jane" object contains a pointer to the "Bob" object...
>>> bob.friend = jane
登入後複製
我們在上面的程式碼片斷中所做的是設定了一些迴圈參照。名字為 Jane 的物件包含一個指向名字為 Bob 的物件的指標,反之亦然。當我們做下面的事情時,情況就變得有趣了。
>>> del jane
>>> del bob
登入後複製
我們現在已經刪除了從名稱空間到物件的指標。現在,我們完全不能存取那些 MyNameClass 物件了--但我們並沒有收到告訴我們它們即將被刪除的列印資訊。這是因為這些物件仍有參照,包含在彼此之間,因此它們的參照計數不是 0 。
我們在這裡建立的是一個迴圈隔離體;在這個結構中,每個物件在迴圈中至少有一個參照,使其保持活力,但迴圈中的所有物件都不能從名稱空間中被存取。
下面是我們建立一個迴圈隔離時的直觀表現。
首先,我們建立兩個物件,每個物件在名稱空間中都有一個名字。
接下來,我們通過在每個物件上新增一個指標來連線我們的兩個物件。
最後,我們通過刪除兩個物件的原始名稱來從名稱空間中刪除指標。在這一點上,這兩個物件從名稱空間中是不可存取的,但每個物件都包含一個指向另一個物件的指標,所以它們的參照計數不是零。
所以,很明顯,參照計數本身並不足以保持執行時的工作記憶體中沒有無用的、不可回收的物件。這就是CPython的垃圾收集器發揮作用的地方。
【相關推薦:Python3視訊教學 】
以上就是什麼是Python垃圾回收機制中的參照計數的詳細內容,更多請關注TW511.COM其它相關文章!