Surprisingly, there's no explicit documentation for __weakref__
. Weak references are explained here. __weakref__
is also shortly mentioned in the documentation of __slots__
. But I could not find anything about __weakref__
itself.
What exactly is __weakref__
?
- Is it just a member acting as a flag: If present, the object may be weakly-referenced?
- Or is it a function/variable that can be overridden/assigned to get a desired behavior? How?
The
__weakref__
variable is an attribute which makes the object to support the weak references and preserving the weak references to object.The python documentation has explained it as following:
Therefore, the duty of weak references is supplying the conditions for an object in order to be able to be garbage collected regardless of its type and the scope.
And about the
__slots__
, we can first look into the documentation, which explains it very well:Now, since by using
__slots__
you will control the demanded storage for your attribute, it actually prevents the automatic creation of__dict__
and__weakref__
for each instance. Which the__weakref__
is the necessary variable of each object in order to be able to deal with weak references.Also, in addition to all these the documentation for
object.__slots__
class says:So, In a nutshell, we can conclude that
__slots__
are for managing the storage allocation manually and since__weakref__
is the license of accepting the weak references for objects which is related to storage (because of the ability of being garbage collected), therefore__slots__
will control the__weakref__
as well as controlling the__dict__
attribute.Also documentation has shown you the way of making an object to support the weak references along side of using
__slots__
:Here is an example in python 3.X:
But in python 2.7 there, although the documentation is like the aforementioned docs, creating a weak reference from instances that doesn't provide the
__weakref__
variable in their__slots__
names doesn't raise aTypeError
:__weakref__
is just an opaque object that references all the weak references to the current object. In actual fact it's an instance ofweakref
(or sometimesweakproxy
) which is both a weak reference to the object and part of a doubly linked list to all weak references for that object.It's just an implementation detail that allows the garbage collector to inform weak references that its referent has been collected, and to not allow access to its underlying pointer anymore.
The weak reference can't rely on checking the reference count of the object it refers to. This is because that memory may have been reclaimed and is now being used by another object. Best case scenario the VM will crash, worst case the weak reference will allow access to an object it wasn't originally referring to. This is why the garbage collector must inform the weak reference its referent is no longer valid.
See weakrefobject.h for the structure and C-API for this object. And the implementation detail is here
[Edit 1: Explain the linked list nature and when weakrefs are re-used]
Interestingly enough, the official documentation is somewhat non-enlightening on this topic:
The
type
object documentation on the topic does not seem to help things along too much:Weak references form a linked list. The head of that list (the first weak reference to an object) is available via
__weakref__
. Weakrefs are re-used whenever possible, so the list (not a Python list!) typically is either empty or contains a single element.Example:
When you first use
weakref.ref()
, you create a new weak reference chain for the target object. The head of this chain is the new weakref and gets stored in the target object's__weakref__
:As we can see,
b
is re-used. We can force python to create a new weakref, by e.g. adding a callback parameter:Now
b is a.__weakref__
, andc
is the second reference in the chain. The reference chain is not directly accessible from Python code. We see only the head element of the chain (b
), but not how the chain continues (b
->c
).So
__weakref__
is the head of the internal linked list of all the weak references to the object. I cannot find any piece of official documentation where this role of__weakref__
is concisely explained, so one should probably not rely on this behavior, as it is an implementation detail.