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?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.