如果循环中的对象没有自定义,则不必担心引用循环__del__
方法,因为 Python 可以(并且将会)以任何顺序销毁对象。
如果您的自定义方法确实有__del__
方法中,Python 根本不知道一个对象的删除是否会影响另一个对象的删除。假设当一个对象被删除时,它会设置一些全局变量。因此,物体会留在周围。作为快速测试,您可以进行__del__
打印一些东西的方法:
class Deletor(str):
def __del__(self):
print(self, 'has been deleted')
a = Deletor('a') # refcount: 1
del a # refcount: 0
Outputs:
a has been deleted
但如果你有这样的代码:
a = Deletor('a') # refcount: 1
a.circular = a # refcount: 2
del a # refcount: 1
它不输出任何内容,因为 Python 无法安全删除a
。它变成了“无法收集的物品”,并且可以在以下位置找到:gc.garbage https://docs.python.org/3/library/gc.html#gc.garbage †
对此有两种解决方案。这weakref
(这不会增加引用计数):
# refcount: a b
a = Deletor('a') # 1 0
b = Deletor('b') # 1 1
b.a = a # 2 1
a.b = weakref.ref(b) # 2 1
del a # 1 1
del b # 1 0
# del b kills b.a # 0 0
Outputs:
b has been deleted
a has been deleted
(注意如何b
先删除后才能删除a
)
您可以手动删除周期(如果您可以跟踪它们):
# refcount a b
a = Deletor('a') # 1 0
b = Deletor('b') # 1 1
b.a = a # 2 1
a.b = b # 2 2
del b # 2 1
print('del b')
del a.b # 2 0
# b is deleted, now dead
# b.a now dead # 1 0
print('del a.b')
del a # 0 0
print('del a')
Outputs:
del b
b has been deleted
del a.b
a has been deleted
del a
注意如何b
被删除after a.b
被删除。
† 从 Python 3.4 开始,事情发生了变化,因为PEP 442 https://www.python.org/dev/peps/pep-0442/. __del__
即使在引用循环中的对象上也可能被调用,并且语义略有不同,因此成为不可收集对象稍微困难一些。
A weakref
仍然有帮助,因为它对垃圾收集器的强度较小,并且可以更早地回收内存。