Python中的__weakref__到底是什么?
What exactly is __weakref__ in Python?
令人惊讶的是,__weakref__
没有明确的文档。解释了弱引用 here。 __weakref__
在 __slots__
的文档中也有简短提及。但是我找不到关于 __weakref__
本身的任何信息。
__weakref__
到底是什么?
- 它只是一个充当标志的成员:如果存在,该对象可能是弱引用的?
- 还是 function/variable 可以 overridden/assigned 以获得所需的行为?怎么样?
在我们讨论什么是 __weakref__
之前,我们需要定义弱引用的概念。
在大多数文本和来源中,弱引用通常被定义为不保护引用对象(引用对象)不被垃圾收集器收集的引用。
但是垃圾收集到底是什么?
垃圾收集只是当内存不再被任何 reference/pointer used/reached 时释放内存的过程。 Python 通过称为 引用计数 的技术执行垃圾收集( 以及用于检测和中断引用循环的循环垃圾收集器 ) .使用 引用计数 ,当对象的引用数为 0 时,GC 会在对象变得不可访问时立即收集对象。(有关更多信息,请阅读 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types)
现在,弱引用执行不保护对象不被 GC 收集的任务的方式,或者更确切地说是它们导致对象被回收的方式被 GC 收集的是(在使用引用计数而不是跟踪技术的 GC 的情况下)它们不会被计为 reference.Otherwise,如果被计入,它们将被称为强引用。
现在,当我们在 Python 中定义对象时,由于默认情况下所有引用都是强引用,为了创建对象的弱引用,您需要使用 weakref
模块。每当您创建对对象的弱引用时,该引用都可以通过 __weakref__
属性访问。
这是一个例子:
In [51]: class A:
...: def sample_method(self):
...: return "I'm a sample method"
...:
...:
In [52]: a = A()
In [53]: a.__weakref__
In [54]: # There's no weak reference defined
In [55]: import weakref
In [56]: r1 = weakref.ref(a)
In [57]: a.__weakref__
Out[57]: <weakref at 0x7f515b7583b0; to 'A' at 0x7f51680f4ee0>
In [58]: r1 is a.__weakref__
Out[58]: True
# As you can see they both point to one object
# which means that a.__weakref__ is precisely r1
# Also, using weakref.ref always one reference to
# the object will be created (singleton)
In [60]: r2 = weakref.ref(a)
In [62]: r1 is r2
Out[62]: True
有趣的是,language documentation 在这个话题上有点没有启发性:
Without a __weakref__
variable for each instance, classes defining __slots__
do not support weak references to its instances. If weak reference support is needed, then add '__weakref__'
to the sequence of strings in the __slots__
declaration.
When a type’s __slots__
declaration contains a slot named __weakref__
, that slot becomes the weak reference list head for instances of the type, and the slot’s offset is stored in the type’s tp_weaklistoffset
.
弱引用形成堆栈。该堆栈的顶部(对对象的最新弱引用)可通过 __weakref__
获得。 Weakrefs 会尽可能重复使用,因此堆栈通常为空或包含单个元素。
例子
当你第一次使用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
是堆栈中的新弱引用。
__weakref__
只是一个不透明的对象,引用了当前对象的所有弱引用。事实上,它是 weakref
(或有时 weakproxy
)的一个实例,它既是对该对象的弱引用,也是该对象所有弱引用的双向链表的一部分。
这只是一个实现细节,允许垃圾收集器通知弱引用其引用已被收集,并且不再允许访问其底层指针。
弱引用不能依赖于检查它引用的对象的引用计数。这是因为该内存可能已被回收并且现在正被另一个对象使用。最好的情况是 VM 会崩溃,最坏的情况是弱引用将允许访问它最初未引用的对象。这就是垃圾收集器必须通知弱引用其引用不再有效的原因。
见weakrefobject.h for the structure and C-API for this object. And the implementation detail is here
令人惊讶的是,__weakref__
没有明确的文档。解释了弱引用 here。 __weakref__
在 __slots__
的文档中也有简短提及。但是我找不到关于 __weakref__
本身的任何信息。
__weakref__
到底是什么?
- 它只是一个充当标志的成员:如果存在,该对象可能是弱引用的?
- 还是 function/variable 可以 overridden/assigned 以获得所需的行为?怎么样?
在我们讨论什么是 __weakref__
之前,我们需要定义弱引用的概念。
在大多数文本和来源中,弱引用通常被定义为不保护引用对象(引用对象)不被垃圾收集器收集的引用。
但是垃圾收集到底是什么?
垃圾收集只是当内存不再被任何 reference/pointer used/reached 时释放内存的过程。 Python 通过称为 引用计数 的技术执行垃圾收集( 以及用于检测和中断引用循环的循环垃圾收集器 ) .使用 引用计数 ,当对象的引用数为 0 时,GC 会在对象变得不可访问时立即收集对象。(有关更多信息,请阅读 https://docs.python.org/3/reference/datamodel.html#objects-values-and-types)
现在,弱引用执行不保护对象不被 GC 收集的任务的方式,或者更确切地说是它们导致对象被回收的方式被 GC 收集的是(在使用引用计数而不是跟踪技术的 GC 的情况下)它们不会被计为 reference.Otherwise,如果被计入,它们将被称为强引用。
现在,当我们在 Python 中定义对象时,由于默认情况下所有引用都是强引用,为了创建对象的弱引用,您需要使用 weakref
模块。每当您创建对对象的弱引用时,该引用都可以通过 __weakref__
属性访问。
这是一个例子:
In [51]: class A:
...: def sample_method(self):
...: return "I'm a sample method"
...:
...:
In [52]: a = A()
In [53]: a.__weakref__
In [54]: # There's no weak reference defined
In [55]: import weakref
In [56]: r1 = weakref.ref(a)
In [57]: a.__weakref__
Out[57]: <weakref at 0x7f515b7583b0; to 'A' at 0x7f51680f4ee0>
In [58]: r1 is a.__weakref__
Out[58]: True
# As you can see they both point to one object
# which means that a.__weakref__ is precisely r1
# Also, using weakref.ref always one reference to
# the object will be created (singleton)
In [60]: r2 = weakref.ref(a)
In [62]: r1 is r2
Out[62]: True
有趣的是,language documentation 在这个话题上有点没有启发性:
Without a
__weakref__
variable for each instance, classes defining__slots__
do not support weak references to its instances. If weak reference support is needed, then add'__weakref__'
to the sequence of strings in the__slots__
declaration.
When a type’s
__slots__
declaration contains a slot named__weakref__
, that slot becomes the weak reference list head for instances of the type, and the slot’s offset is stored in the type’stp_weaklistoffset
.
弱引用形成堆栈。该堆栈的顶部(对对象的最新弱引用)可通过 __weakref__
获得。 Weakrefs 会尽可能重复使用,因此堆栈通常为空或包含单个元素。
例子
当你第一次使用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
是堆栈中的新弱引用。
__weakref__
只是一个不透明的对象,引用了当前对象的所有弱引用。事实上,它是 weakref
(或有时 weakproxy
)的一个实例,它既是对该对象的弱引用,也是该对象所有弱引用的双向链表的一部分。
这只是一个实现细节,允许垃圾收集器通知弱引用其引用已被收集,并且不再允许访问其底层指针。
弱引用不能依赖于检查它引用的对象的引用计数。这是因为该内存可能已被回收并且现在正被另一个对象使用。最好的情况是 VM 会崩溃,最坏的情况是弱引用将允许访问它最初未引用的对象。这就是垃圾收集器必须通知弱引用其引用不再有效的原因。
见weakrefobject.h for the structure and C-API for this object. And the implementation detail is here