Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is class.__weakref__ not None, while instance.__weakref__ is None?

__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?

like image 666
direprobs Avatar asked Oct 19 '25 13:10

direprobs


1 Answers

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>
like image 172
Martijn Pieters Avatar answered Oct 22 '25 05:10

Martijn Pieters



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!