Mic*_*ael 57 python python-3.x python-internals
令人惊讶的是,没有明确的文档__weakref__
.这里解释了弱引用.__weakref__
也很快在文档中提到__slots__
.但我找不到任何关于__weakref__
它自己的东西.
到底是__weakref__
什么? - 它只是一个作为标志的成员:如果存在,该对象可能被弱引用? - 或者它是一个可以被覆盖/分配以获得所需行为的函数/变量?怎么样?
Dun*_*nes 45
__weakref__
只是一个不透明的对象,它引用了对当前对象的所有弱引用.实际上,它是weakref
(或有时weakproxy
)的一个实例,它既是对象的弱引用,也是对该对象的所有弱引用的双向链表的一部分.
它只是一个实现细节,它允许垃圾收集器通知弱引用它已经收集了它的引用,并且不再允许访问它的底层指针.
弱引用不能依赖于检查它引用的对象的引用计数.这是因为该内存可能已被回收,现在正由另一个对象使用.最好的情况是VM会崩溃,最坏的情况是弱引用将允许访问它最初没有引用的对象.这就是为什么垃圾收集器必须通知弱引用它的引用不再有效.
有关此对象的结构和C-API,请参阅weakrefobject.h.实现细节在这里
dhk*_*hke 28
[编辑1:解释链表性质以及重复使用弱化时]
有趣的是,官方文档在这个主题上有点不具启发性:
如果没有
__weakref__
每个实例的变量,则定义的类__slots__
不支持对其实例的弱引用.如果需要弱引用支持,则__weakref__
在__slots__
声明中添加字符串序列.
关于该主题的type
对象文档似乎没有太多帮助:
当类型的
__slots__
声明包含一个名为的槽时__weakref__
,该槽成为该类型实例的弱引用列表头,并且槽的偏移量存储在类型的中tp_weaklistoffset
.
弱引用形成链表.该列表的头部(对象的第一个弱引用)可通过__weakref__
.尽可能重用weakrefs,因此列表(不是Python列表!)通常为空或包含单个元素.
示例:
首次使用时weakref.ref()
,将为目标对象创建新的弱引用链.这个链的头部是新的weakref并存储在目标对象中__weakref__
:
>>> import weakref
>>> class A(object): pass
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(b)
>>> print(b is c is a.__weakref__)
True
Run Code Online (Sandbox Code Playgroud)
我们可以看到,b
重新使用.我们可以强制python创建一个新的weakref,例如添加一个回调参数:
>>> def callback():
>>> pass
>>> a = A()
>>> b = weakref.ref(a)
>>> c = weakref.ref(b, callback)
>>> print(b is c is a.__weakref__)
False
Run Code Online (Sandbox Code Playgroud)
现在b is a.__weakref__
,它c
是链中的第二个参考.Python代码无法直接访问引用链.我们只看到chain(b
)的head元素,但不知道链如何继续(b
- > c
).
__weakref__
所有对象的弱引用的内部链表的头部也是如此.我找不到任何官方文档,其中__weakref__
简要解释了这个角色,因此可能不应该依赖于这种行为,因为它是一个实现细节.
Kas*_*mvd 16
的__weakref__
变量是这使得对象以支持弱引用和保存弱引用到对象的属性.
python文档解释如下:
当对引用的唯一剩余引用是弱引用时,垃圾收集可以自由地销毁引用并将其内存重用于其他内容.
因此,弱引用的职责是为对象提供条件,以便能够被垃圾收集,而不管其类型和范围如何.
关于这一点__slots__
,我们可以先查看文档,这很好地解释了它:
默认情况下,类的实例具有属性存储的字典.这会浪费具有很少实例变量的对象的空间.在创建大量实例时,空间消耗会变得很严重.
可以通过
__slots__
在类定义中定义来覆盖默认值.该__slots__
声明需要实例变量和储备只够空间的序列中的每个实例来保存每个变量的值.保存空间是因为__dict__
没有为每个实例创建空间.
现在,因为通过使用__slots__
您将控制属性的所需存储,它实际上阻止了自动创建__dict__
和__weakref__
为每个实例.这__weakref__
是每个对象的必要变量,以便能够处理弱引用.
此外,除了所有这些,object.__slots__
课程文档说:
可以为此类变量分配字符串,可迭代或具有实例使用的变量名称的字符串序列.
__slots__
为声明的变量保留空间,并阻止自动创建__dict__
和__weakref__
为每个实例创建.
因此,简而言之,我们可以得出结论,__slots__
用于手动管理存储分配,因为__weakref__
是接受与存储相关的对象的弱引用的许可(因为能够被垃圾收集),因此__slots__
将控制__weakref__
为以及控制__dict__
属性.
此外,文档还向您展示了如何使用一个对象来支持弱引用__slots__
:
如果没有
__weakref__
每个实例的变量,则定义的类__slots__
不支持对其实例的弱引用.如果需要弱引用支持,则'__weakref__'
在__slots__
声明中添加字符串序列.
这是python 3.X中的一个例子:
>>> class Test:
... __slots__ = ['a', 'b']
...
>>>
>>> import weakref
>>>
>>> t = Test()
>>>
>>> r = weakref.ref(t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create weak reference to 'Test' object
>>>
>>> class Test:
... __slots__ = ['a', 'b', '__weakref__']
...
>>> t = Test()
>>> r = weakref.ref(t)
>>>
>>> t.__weakref__
<weakref at 0x7f735bc55d68; to 'Test' at 0x7f735bc51fc8>
Run Code Online (Sandbox Code Playgroud)
但是在python 2.7中,尽管文档与上述文档类似,但是从不__weakref__
在其__slots__
名称中提供变量的实例创建弱引用不会引发TypeError
:
>>> class Test:
... __slots__ = ['a', 'b']
...
>>> t = Test()
>>>
>>> r = weakref.ref(t)
>>>
>>> r
<weakref at 0x7fe49f4185d0; to 'instance' at 0x7fe4a3e75f80>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11101 次 |
最近记录: |