令人惊讶的是,没有关于 __weakref__
的明确文档。 此处 解释了弱引用。 __weakref__
在 __slots__
的文档中也有简短提及。但我找不到任何关于 __weakref__
本身的信息。
__weakref__
究竟是什么? - 它只是一个充当标志的成员:如果存在,该对象可能是弱引用的? - 或者它是一个可以被覆盖/分配以获得所需行为的函数/变量?如何?
原文由 Michael 发布,翻译遵循 CC BY-SA 4.0 许可协议
令人惊讶的是,没有关于 __weakref__
的明确文档。 此处 解释了弱引用。 __weakref__
在 __slots__
的文档中也有简短提及。但我找不到任何关于 __weakref__
本身的信息。
__weakref__
究竟是什么? - 它只是一个充当标志的成员:如果存在,该对象可能是弱引用的? - 或者它是一个可以被覆盖/分配以获得所需行为的函数/变量?如何?
原文由 Michael 发布,翻译遵循 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 许可协议
4 回答4.4k 阅读✓ 已解决
4 回答3.8k 阅读✓ 已解决
1 回答3k 阅读✓ 已解决
3 回答2.1k 阅读✓ 已解决
1 回答4.5k 阅读✓ 已解决
1 回答3.8k 阅读✓ 已解决
1 回答2.8k 阅读✓ 已解决
__weakref__
只是一个不透明的对象,引用了当前对象的所有弱引用。事实上,它是weakref
(或有时weakproxy
)的一个实例,它既是对该对象的弱引用,也是该对象所有弱引用的双向链表的一部分。它只是一个实现细节,允许垃圾收集器通知弱引用其引用已被收集,并且不再允许访问其底层指针。
弱引用不能依赖于检查它引用的对象的引用计数。这是因为该内存可能已被回收并且现在正被另一个对象使用。最好的情况是 VM 会崩溃,最坏的情况是弱引用将允许访问它最初未引用的对象。这就是垃圾收集器必须通知弱引用其引用不再有效的原因。
有关此对象的结构和 C-API,请参阅 weakrefobject.h 。实现细节在 这里