4

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

1
  • 1
    "this means that A.__weakref__ is the same as A().__weakref__" - clearly not, so your assumption that "instances inherit __weakref__ from the class" is incorrect. A.__weakref__ is A().__weakref__ evaluates to False. Commented Apr 24, 2016 at 20:34

1 Answer 1

5

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>
Sign up to request clarification or add additional context in comments.

1 Comment

Can I ask why did you mention : "to bypass the normal type.__getattribute__() binding behaviour" ? I can see that print(A.__weakref__ is A.__dict__["__weakref__"]) is True. I mean isn't __weakref__ a class attribute which happens to be a decsriptor in the class's namespace? Does type metaclass do something in it's __getattribute__ method for "__weakref__" key?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.