2012-12-03 24 views
3

__del__的Python文檔解釋了當對象的引用計數減爲零時,可以調用對象的__del__方法。它是否總是立即被調用(即同步)?或者有可能將這種方法稱爲「將來的某個時刻」?python是否總是同時調用__del__?

此外,這個問題的答案是否適用於Python?或者是授予語言實現的一些緯度? (我用CPython的。)

對於這個問題,以下假設:

  • 有問題的對象從object繼承。
  • 有問題的對象有一個自定義的__del__實現。
  • 對象的自定義__del__實現不會創建任何對象的新引用。
  • 有問題的對象不是參考週期的一部分。
  • 解釋器並未處於關閉狀態。

從我所知道的來看,圍繞這個話題似乎有很多困惑。在努力側步一些不必要的討論,讓我給不可接受的答案的一些例子:「!不要用__del__這是令人困惑的」

  • 」不要使用__del__!它不是'pythonic'。「
  • 「請勿使用__del__,請改爲使用上下文管理器。」
  • 如果沒有引用可信來源,任何可以斷定什麼是或不能保證的答案。 (請隨意引用其他SO答案,但不要將它們作爲您的唯一來源。在這種情況下,「可信」意味着來自文檔或信譽良好的人,或者甚至是CPython源本身。)

要改寫這個問題用一個例子,考慮下面的代碼:

class C(object): 
    def __init__(self, i): 
     self.i = i 

    def __del__(self): 
     print "C.__del__:", self.i 

print "Creating list" 
l = [C(0), C(1), C(2)] 

print "Popping item 1" 
l.pop(1) 

print "Clearing list" 
l = [] 

print "Exiting..." 

產生以下輸出:

$ python test_del.py 
Creating list 
Popping item 1 
C.__del__: 1 
Clearing list 
C.__del__: 2 
C.__del__: 0 
Exiting... 

請注意,在這個例子中,__del__同步呼叫。這種行爲是否由語言保證? (請記住上面列出的假設。)

+0

你的用例答案很重要? –

+0

如果我可以依靠這種行爲,它允許一個更清潔的API設計。我沒有強迫我的圖書館的用戶記得在我給它們的對象上調用一些特殊的「cleanUp()」函數,我只需將必要的清理代碼放在__del__中即可。例如,這是C++中良好的基於​​RAII的API設計的基礎。 –

+1

但是,當* __del__被調用時,知道如何改變? (在任何情況下,該對象都將被刪除*) –

回答

3

從Python語言參考(Python的2.7.3版),Chapter 3, Data model

的對象從未明確銷燬;然而,當他們無法到達時,他們可能會被垃圾收集。允許實現推遲垃圾收集或完全忽略垃圾收集 - 只要沒有收集到仍然可以訪問的對象,實施質量如何實施垃圾收集就成了一個問題。

CPython的實現細節: CPython的目前使用的參考計數方案與(可選)延遲環狀連接的垃圾,其中,一旦收集大多數對象,因爲它們變得不可達的檢測,但不能保證,以收集垃圾含循環參考。有關控制循環垃圾收集的信息,請參見gc模塊的文檔。其他實現的行爲不同,CPython可能會改變。不要依賴對象在無法訪問時立即敲定(例如:始終關閉文件)。

+0

感嘆。我怎麼錯過了?我花了我的時間閱讀'__del__'本身的文檔,這並沒有說明什麼是實現定義。它只說'__del__'被稱爲「當x的引用計數達到零時調用」。但是你引用的段落明確表示爲白天。 –

+0

接受這個答案,但也請參閱@安德魯的答案(下面),這個鏈接與這個關於PyPy的討論非常相關。 –

1

該行爲不受語言保證。例如,請參見PyPy's documentation on their garbage collection scheme,其中明確指出在PyPy中調用__del__的時間與CPython不同。

如果你的對象不是參考週期的一部分,那麼我明白這種行爲在CPython中是可靠的,但我不知道有任何明確的保證。

+0

偉大的鏈接,謝謝。它給了我三個印象:(1)語言規範是模糊的,但它似乎意味着立即刪除行爲是預期的。 (2)這是一個任意的決定,可能受到CPython實施的影響。 (3)由於PyPy,Jython和IronPython的作者不會採用CPython的引用計數方案,所以它實際上*無關緊要。「官方」答案是什麼。這個事實意味着'__del__'行爲事實上是「未定義的」,不管標準作者是否關心。 –

+0

我不能說語言規範在這一點上是否不清楚,但從實際的角度來看,我同意這種行爲是未定義的,不應該使用,除非您確實希望代碼在對象從內存中刪除(這似乎是一個不太可能的用例)。 –

+0

另外,注意:即使CPython是唯一的目標,我也不覺得應該編寫假定對象不是參考週期一部分的代碼。由於對象本身的外部情況,對象可以成爲參考週期的一部分。 –

相關問題