我发现当涉及循环引用时,似乎不会执行自定义__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
操作?
答案 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__
的时间是实际的引用计数被更改的时间。)