2012-03-20 50 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