Reputation: 4633
__weakref__
is related to weak references. I get the whole idea behind weak references and where I might use them. The only thing that I don't get is described in the following:
An instance doesn't have the attribute __weakref__
itself, distinct from the class, therefore the instance inherits __weakref__
from the class, this means that A.__weakref__
should be the same as A().__weakref__
:
>>> class A: pass
...
>>> A().__dict__ # Each instance starts out as an empty namespace
{}
>>> A.__weakref__ is None;
False
>>> A().__weakref__ is None #But this is True!
True
Why is A.__weakref__
not None
while instance.__weakref__
is None
although instances inherit __weakref__
from the class?
Upvotes: 4
Views: 477
Reputation: 1122372
A class has a __weakref__
data descriptor attribute; this acts just like a property
; only when you access the attribute on an instance is it automatically bound. The actual data for a weak reference is stored in a C structure, part of the data structure Python uses to represent classes and instances in memory.
As such, instances don't need their own __weakref__
attribute. The class descriptor is bound to the instance data structure, and the C code then just looks in the right C struct to retrieve the information needed.
Accessing the attribute on the class, produces the descriptor object itself. This is not None
; it is the descriptor object. On an instance, the bound attribute produces the weak reference. No weak reference means None
is returned.
You can re-create the descriptor behaviour by accessing the object via A.__dict__['__weakref__']
(to bypass the normal type.__getattribute__()
binding behaviour), then directly calling __get__
on that:
>>> import weakref
>>> class A(object): pass
...
>>> a = A()
>>> A.__weakref__
<attribute '__weakref__' of 'A' objects>
>>> descriptor = A.__dict__['__weakref__']
>>> descriptor.__get__(None, A)
<attribute '__weakref__' of 'A' objects>
>>> a = A()
>>> a.__weakref__ is None
True
>>> descriptor.__get__(a) is None
True
>>> wr = weakref.ref(a) # add a weak reference
>>> wr
<weakref at 0x10bd86d68; to 'A' at 0x10bad3588>
>>> a.__weakref__
<weakref at 0x10bd86d68; to 'A' at 0x10bad3588>
>>> descriptor.__get__(a)
<weakref at 0x10bd86d68; to 'A' at 0x10bad3588>
Upvotes: 5