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:
when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else.
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:
By default, instances of classes have a dictionary for attribute storage. This wastes space for objects having very few instance variables. The space consumption can become acute when creating large numbers of instances.
The default can be overridden by defining __slots__
in a class definition. The __slots__
declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__
is not created for each instance.
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:
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __slots__
reserves space for the declared variables and prevents the automatic creation of __dict__
and __weakref__
for each instance.
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__
:
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.
Here is an example in 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>
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 a TypeError
:
>>> class Test:
... __slots__ = ['a', 'b']
...
>>> t = Test()
>>>
>>> r = weakref.ref(t)
>>>
>>> r
<weakref at 0x7fe49f4185d0; to 'instance' at 0x7fe4a3e75f80>