Interestingly enough, the language documentation is somewhat non-enlightening on this topic:
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.
The C API documentation is more useful:
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
.
Weak references form a stack. The top of that stack (the most recent weak reference to an object) is available via __weakref__
. Weakrefs are re-used whenever possible, so the stack is typically either empty or contains a single element.
Example
When you first use weakref.ref()
, you create a new weak reference stack for the target object. The top of this stack is the new weak reference and gets stored in the target object’s __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>]
As you can see, c
re-uses b
. You can force Python to create a new weak reference by passing a callback argument:
>>> 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>]
Now c
is a new weak reference in the stack.
obj.__weakref__
remembers the weak referencewr
pointing onobj
an will be used to invalidatewr
whenobj
is garbage collected? – Slabber