2012-03-20 47 views
4

引用計數到達零後多久是__del__方法調用?該語言是否承諾在任何其他使用代碼可以執行之前立即完成?或者,每個實現都可以按照自己喜歡的方式進行,可能會延遲任意長的電話號碼__del__參考計數下降到零後,多久會調用__del__?

請忽略程序即將退出的情況(我假設它意味着給定塊中的最後一條語句已完成,並且堆棧爲空)。我明白在這種情況下,沒有關於__del__的承諾;它甚至可能根本不會被調用。

另外,我知道引用計數可能由於週期等原因而不是零。在這裏我不關心這個問題(我在問一個單獨的問題)。

+3

通過說「引用計數」,你已經做出了假設。 – 2012-03-20 23:40:49

+1

如果您考慮實施它,請首先閱讀**胖胖的紅色警告**:http://docs.python.org/reference/datamodel.html#object.__del__ – ThiefMaster 2012-03-20 23:43:38

+0

您基本上不想用'__del__'做任何事情:http://blogs.msdn.com/b/oldnewthing/archive/2010/08/09/10047586.aspx – SingleNegationElimination 2012-03-20 23:46:44

回答

11

Python在調用__del__時不作任何保證,或者不管它是否全部調用。實際上,如果對象是引用循環的一部分,則不可能調用__del__方法,因爲即使將整個循環清理乾淨,Python也無法決定在哪裏中斷循環以及以何種順序排列__del__方法(如果有的話)應該被調用。由於__del__的語義很奇怪(爲了調用__del__,對象的引用次數暫時增加,並且__del__方法可以通過在其他地方存儲引用來防止對象被破壞),但在其他實現中會發生什麼crapshoot。 (我不記得在當前的Jython的具體細節,但它改變了過去幾次。)

這就是說,在CPython的,如果__del__被調用時,它立即調用引用計數下降到零(因爲引用計數是唯一的出路__del__方法被調用,並在實際引用計數改變的唯一機會CPython的有呼叫__del__的是。)

+2

所以基本上如果你不得不問,不要這樣做。 – 2012-03-20 23:53:04

+0

'gc'模塊可以打破參考週期。 – 2012-03-21 00:02:58

+1

'gc'模塊不能使用'__del__'方法破壞涉及對象的引用循環。相反,它把它們塞進'gc.garbage'中,忘記它們。如果你知道如何分解它們,你可以通過'gc.garbage'來打破這些循環,但'gc'模塊不會爲你做。 – 2012-03-21 00:13:33

3

請閱讀CPython object.__del__文檔。這說明了大部分需要說明的內容,但是具體實現方式是:大多數其他的Python實現不使用refcounting,所以你不應該依賴它在某個時候被調用(或者甚至被調用)的功能。它在銷燬時會被調用,其實現方式會有所不同。

5

關於你應該永遠使用__del__的唯一原因是爲了幫助垃圾收集器收集更多垃圾。例如,如果您正在實現將共享庫附加到正在運行的進程的​​模塊,那麼在收集最後一個對其的引用時卸載這些庫是有意義的,以允許將其地址空間用於其他內容。

對於管理其他種資源,你幾乎肯定不想與垃圾收集器有任何關係。正確的工具是context managers。與變量作用域用於RAII的C++或Ada等語言不同,python使用with語句以及具有__enter____exit__方法的對象。許多建於Python類型使用這個確切的機制,以確保最終確定步驟實際發生:

>>> x = file("foo", 'w') 
>>> x.closed 
False 
>>> with x: 
...  x.write("bar") 
... 
>>> x.closed 
True 

這也是但從蟒禪宗的角度來看非常有價值:

明確優於隱式。

因爲很清楚發生了清理,所以明確地這樣寫。這比清理髮生的情況要好得多,當一些隱藏的變量(引用計數,如果存在的話,並且它不在PyPy或IronPython或Jython中)達到某個特定值時,可能會「神奇地」發生。

+1

Weakref回調是一種更好的方式來實現您建議使用'__del__'方法的清理方式,因爲它們不會阻止週期清理。 「__del__」存在的唯一原因是因爲它早於對Python的非實現計算以及弱參數的考慮。 – 2012-03-21 00:34:41