参考计数降到零后,多长时间调用`__del__`?

时间:2012-03-20 23:38:44

标签: python garbage-collection python-3.x destructor

引用计数达到零后多久调用__del__方法?在任何其他使用代码执行之前,语言是否承诺立即完成?或者每个实现都可以做自己喜欢的事情,可能会延迟对__del__任意长时间的调用?

请忽略程序即将退出时的情况(我假设它意味着给定块中的最后一个语句已完成,并且堆栈为空)。我理解在这种情况下,__del__没有任何承诺;甚至根本不需要它。

另外,我知道由于周期等原因引用计数可能不为零。我在这里并不关心(我正在问一个单独的问题)。

3 个答案:

答案 0 :(得分:11)

Python不保证何时调用__del__,或是否完全调用。实际上,如果对象是引用循环的一部分,则不太可能调用__del__方法,因为即使整个循环被清理,Python也无法决定在哪里打破循环,应该调用__del__方法(如果有的话)的顺序。由于__del__相当古怪的语义(为了调用__del__,临时增加了对象的引用计数,__del__方法可以通过在某处存储引用来防止对象的破坏否则)在其他实现中发生的事情有点像crapshoot。 (我不记得当前Jython中的确切细节,但过去已经改变了几次。)

也就是说,在CPython中,如果调用 __del__,只要引用计数降为零就会调用它(因为引用计数是__del__方法的唯一方法调用,CPython调用__del__的唯一机会就是改变实际的引用次数。)

答案 1 :(得分:5)

关于你应该使用__del__的唯一原因是帮助垃圾收集器收集更多垃圾。例如,如果您正在实现诸如将共享库附加到正在运行的进程的ctypes模块之类的东西,则在收集对它的最后一个引用时卸载这些库是有意义的,以允许其地址空间用于别的什么。

对于管理其他种类的资源,您几乎肯定不希望与垃圾收集器有任何关系。正确的工具是context managers。与C ++或Ada等语言不同,其中变量作用域用于RAII,python使用with语句以及具有__enter____exit__方法的对象。许多内置的python类型使用这种确切的机制来确保实际完成最终化步骤:

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

从蟒蛇的禅宗角度来看,这也很有价值:

  

明确比隐含更好。

因为很明显发生了清理,所以它是以这种方式明确写出来的。当一些隐藏变量(引用计数,如果存在,并且它不在PyPy或IronPython或Jython中)达到某个特定值时,这比“清理”发生清理的情况要好得多。

答案 2 :(得分:3)

请阅读CPython object.__del__文档。这说明了大部分需要说的内容,但具体是针对具体实施的;大多数其他Python实现不使用引用计数,因此您不应该依赖于在此类和此类时间(甚至根本不被调用)来调用它的功能。它在销毁时被调用 - 这将在实现之间变化。