Python 中的 __weakref__ 到底是什么?

新手上路,请多包涵

令人惊讶的是,没有关于 __weakref__ 的明确文档。 此处 解释了弱引用。 __weakref____slots__ 的文档中也有简短提及。但我找不到任何关于 __weakref__ 本身的信息。

__weakref__ 究竟是什么? - 它只是一个充当标志的成员:如果存在,该对象可能是弱引用的? - 或者它是一个可以被覆盖/分配以获得所需行为的函数/变量?如何?

原文由 Michael 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

__weakref__ 只是一个不透明的对象,引用了当前对象的所有弱引用。事实上,它是 weakref (或有时 weakproxy )的一个实例,它既是对该对象的弱引用,也是该对象所有弱引用的双向链表的一部分。

它只是一个实现细节,允许垃圾收集器通知弱引用其引用已被收集,并且不再允许访问其底层指针。

弱引用不能依赖于检查它引用的对象的引用计数。这是因为该内存可能已被回收并且现在正被另一个对象使用。最好的情况是 VM 会崩溃,最坏的情况是弱引用将允许访问它最初未引用的对象。这就是垃圾收集器必须通知弱引用其引用不再有效的原因。

有关此对象的结构和 C-API,请参阅 weakrefobject.h 。实现细节在 这里

原文由 Dunes 发布,翻译遵循 CC BY-SA 4.0 许可协议

有趣的是, 语言文档 在这个主题上有点没有启发性:

如果没有 __weakref__ 每个实例的变量,定义 __slots__ 的类不支持对其实例的弱引用。如果需要弱引用支持,则将 '__weakref__' 添加到 __slots__ 声明中的字符串序列。

C API 文档 更有用:

当一个类型的 __slots__ 声明包含一个名为 __weakref__ 的插槽时,该插槽成为该类型实例的弱引用列表头,并且该插槽的偏移量存储在该类型的 tp_weaklistoffset

弱引用形成一个栈。该堆栈的顶部(对对象的最新弱引用)可通过 __weakref__ 获得。只要有可能,弱引用就会被重用,因此堆栈通常为空或包含单个元素。

例子

当您第一次使用 weakref.ref() 时,您为目标对象创建了一个新的弱引用堆栈。此堆栈的顶部是新的弱引用,并存储在目标对象的 __weakref__ 中:

 >>> import weakref
>>> class A: pass
...
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(a)
>>> c is b, b is a.__weakref__
True, True
>>> weakref.getweakrefs(a)
[<weakref at 0x10dbe5270; to 'A' at 0x10dbc2fd0>]

如您所见, c 重新使用 b 。您可以通过传递回调参数强制 Python 创建一个新的弱引用:

 >>> import weakref
>>> class A: pass
...
>>> def callback(ref): pass
...
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(a, callback)
>>> c is b, b is a.__weakref__
False, True
>>> weakref.getweakrefs(a)
[<weakref at 0x10dbcfcc0; to 'A' at 0x10dbc2fd0>,
 <weakref at 0x10dbe5270; to 'A' at 0x10dbc2fd0>]

现在 c 是堆栈中的新弱引用。

原文由 dhke 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题