Account().observers
是一个集合引用AccountObserver()
实例,但是AccountObserver().theaccount
是一个参考指向back to the Account()
观察者存储在集合中的实例。这是一个循环引用。
通常,垃圾收集器会检测到此类循环并中断循环,从而使引用计数降至 0 并进行正常清理。然而,对于定义了__del__
方法,就像 David 示例中的类所做的那样。来自蟒蛇2gc模块文档 https://docs.python.org/2/library/gc.html#gc.garbage:
gc.garbage
收集器发现无法访问但无法释放的对象列表(无法收集的对象)。默认情况下,此列表仅包含具有__del__()
方法。具有的对象__del__()
方法 和 是引用循环的一部分导致整个引用循环无法收集,包括不一定在循环中但只能从循环中访问的对象。 Python 不会自动收集此类循环,因为一般来说,Python 不可能猜测运行该程序的安全顺序。__del__()
方法。
所以这个循环不能被打破,因为垃圾收集器拒绝猜测终结器(__del__
方法)首先调用。请注意,随机选择一个是not safe对于具体的例子;如果你打电话Account().__del__
首先,然后是observers
set 被删除,后续调用AccountObserver().__del__
将会失败AttributeError
.
弱引用不参与引用计数;因此,如果AccountObserver().theaccount
使用弱引用来指向相应的Account()
实例代替,然后Account()
如果仅留下弱引用,实例将不会保持活动状态:
class AccountObserver(object):
def __init__(self, theaccount):
self.theaccountref = weakref.ref(theaccount)
theaccount.register(self)
def __del__(self):
theaccount = self.theaccountref()
if theaccount is not None:
theaccount.unregister(self)
def update(self):
theaccount = self.theaccountref()
print("Balance is %0.2f" % theaccount.balance)
def close(self):
print("Account no longer in use")
请注意,我链接到了 Python 2 文档。从 Python 3.4 开始,这不再是正确的,甚至是循环依赖,如示例所示will被清除,如PEP 442 – 安全对象终结 https://www.python.org/dev/peps/pep-0442/已实施:
此 PEP 的主要优点涉及具有终结器的对象,例如具有终结器的对象__del__
方法和带有finally 块的生成器。现在,当这些对象属于引用循环的一部分时,可以回收它们。
这并不是说这不会导致回溯;如果您在 Python 3.6 中执行示例,删除引用并启动垃圾收集运行,您将得到一个回溯Account().observers
设置可能已被删除:
>>> import gc
>>> del a, a_ob
>>> gc.collect()
Account no longer in use
Exception ignored in: <bound method AccountObserver.__del__ of <__main__.AccountObserver object at 0x10e36a898>>
Traceback (most recent call last):
File "<stdin>", line 6, in __del__
File "<stdin>", line 13, in unregister
AttributeError: 'Account' object has no attribute 'observers'
65
回溯只是一个警告,否则,gc.collect()
呼叫成功,僵尸AccountObserver()
and Account()
无论如何,物体都会被收获。