__del__method在涉及循环引用时不执行

时间:2012-06-05 04:42:42

标签: python circular-reference del

我发现当涉及循环引用时,似乎不会执行自定义__del__方法。

以下是示例代码:

class DelClass():
        def __init__(self,a):
            self.prop = a 

        def __del__(self):
            print 'del'



if __name__ == "__main__":

    dc1 = DelClass(None)
    dc2 = DelClass(dc1)#dc2 referring to dc1
    dc1.prop = dc2#dc1 referring to dc2, thus creating circular reference
    del dc1#not executing the custom __del__ method

    dc = DelClass(1)
    del dc#executing the custom __del__ method

为什么会这样?

修改 感谢BrenBarn。我找到了原因。

del something仅将引用计数something递减1.

__del__仅在引用计数达到0时执行。

这是一个测试代码:

import gc

class DelClass():
    def __init__(self,name,a):
        self.name = name
        self.prop = a

    def __del__(self):
        print '#####deleting',self.name

dc1 = DelClass("dc1",None)
dc2 = DelClass("dc2",dc1)#dc2 referring to dc1
dc1.prop = dc2#dc1 referring to dc2, thus creating circular reference
print "before deleting dc1,reference count:",len(gc.get_referrers(dc1))
del dc1#not executing the custom __del__ method
print "after deleting dc1, reference count:",len(gc.get_referrers(dc2.prop))
print "deleting the reference held by dc2"
del dc2.prop
print dc2

输出结果为:

before deleting dc1,reference count: 2
after deleting dc1, reference count: 1
deleting the reference held by dc2
#####deleting dc1
<__main__.DelClass instance at 0x9316dec>
#####deleting dc2

出现了另一个问题:

为什么输出中的最后一行(#####deleting dc2)会发生?

发生了一些隐式del操作?

4 个答案:

答案 0 :(得分:3)

阅读documentation for __del__for the garbage collector__del__不会做你认为它做的事,del也不行。当您执行__del__时,del不一定被调用,并且在循环引用的情况下可能永远不会被调用。所有del都会将引用计数减1。

答案 1 :(得分:2)

自python 3.4起,这不再适用。请参阅PEP-442

答案 2 :(得分:1)

因为垃圾收集器无法知道哪个可以安全地首先删除。

答案 3 :(得分:1)

阅读此link。我想这会对你有帮助。

  

del不会致电__del__

     

del在您使用的方式中删除了一个局部变量。当对象被销毁时调用__del__。 Python作为一种语言并不能保证何时会破坏一个对象。

----更新编辑----

回答Some implicit del operation happens?

阅读本文link将为您提供帮助

  

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

     

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