调用终结者方法和僵尸的次数(PEP 442)

时间:2014-07-14 11:07:36

标签: python python-2.7 python-3.4

我对终结器方法__del__产生了疑问 在清理对象之前调用__del__方法,但此方法甚至可以恢复对象。现在我注意到在Python 2.7中终结器被称为每次对象的引用计数器降为零(即使对象已经复活),在Python3.4中它被称为< em>一次对象的整个生命周期,所以如果它被复活然后它的计数器降到零,则不再调用终结器方法。

PEP 442我在python 3.4中读到这个选择是为了阻止复活僵尸:

  

但是,如果对象已经完成,则不会调用终结器。这阻止我们完成僵尸

我怀疑的是,我无法弄清楚这个解决方案如何阻止我们完成僵尸,你能告诉我一些具体的例子吗?此外,该对象只能复活一次。

2 个答案:

答案 0 :(得分:1)

假设我们有以下类:

class RefCycle:
    def __init__(self):
        self.refcycle = self
    def __del__(self):
        print('finalizing')
        print(self.refcycle)

我们创建并收集一个循环隔离物:

RefCycle()
import gc
gc.collect()

当垃圾收集器检测到循环隔离时,它会调用RefCycle实例的终结器。然后,它开始打破引用。当它清除self.refcycle属性时,对象的引用计数将降为0.

这是最终确定的对象不被重新化的重要地方。如果那个“已经完成”的标志不存在,那么该对象将因refcount变为0而被重新归结。由于垃圾收集器已经弄乱了对象的属性,这将是一件非常糟糕的事情。 “已经最终确定”的标志保护我们免受这种情况的影响。

答案 1 :(得分:0)

我想我找到了一个理由,但如果它不是正确的话,请帮助我。

在PEP 442之后,CI的处理传统上是这样的:

  1. 清除CI对象的Weakrefs,并调用它们的回调。在 至此,对象仍然可以安全使用。
  2. CI成为CT,因为GC会系统地破坏其中的所有已知引用(使用tp_clear函数)。
  3. 无。所有CT对象都应在步骤2中处理掉(作为清除参考文件的副作用);这个系列已经完成。
  4. 新提案将成为:

    1. 清除CI对象的Weakrefs,并调用它们的回调。此时,对象仍然可以安全使用。
    2. 调用所有CI对象的终结器。
    3. 再次遍历CI以确定它是否仍处于隔离状态。如果确定现在可以从CI外部到达CI中的至少一个对象,则中止该集合并且复活整个CI。否则,请继续。
    4. CI成为CT,因为GC会系统地破坏其中的所有已知引用(使用tp_clear函数)。
    5. 无。所有CT对象都应在步骤4中处理掉(作为清除参考文献的副作用);这个系列已经完成。
    6. 因为你可以看到前者的第2步和后者的第4步是相同的,特别是它们现在使用相同的函数tp_clear(并且这里帮助我因为我没有&t; t阅读代码,我不太好读C代码)这个函数,从我在销毁一个对象调用它的终结器之前推断出来的,但因为它已经被调用并且CI可能已经开始CT并且复活一个僵尸将是一个错误,终结器只调用一次。