What is __weakrefoffset__?

Question:

What is the __weakrefoffset__ attribute for? What does the integer value signify?

>>> int.__weakrefoffset__ 
0
>>> class A: 
...     pass 
... 
>>> A.__weakrefoffset__ 
24
>>> type.__weakrefoffset__ 
368
>>> class B: 
...     __slots__ = () 
...
>>> B.__weakrefoffset__
0

All types seem to have this attribute. But there’s no mention about that in docs nor in PEP 205.

Asked By: wim

||

Answers:

In CPython, the layout of a simple type like float is three fields: its type pointer, its reference count, and its value (here, a double). For list, the value is three variables (the pointer to the separately-allocated array, its capacity, and the used size). These types do not support attributes or weak references to save space.

If a Python class inherits from one of these, it’s critical that it be able to support attributes, and yet there is no fixed offset at which to place the __dict__ pointer (without wasting memory by putting it at a large unused offset). So the dictionary is stored wherever there is room, and its offset in bytes is recorded in the type. For base classes where the size is variable (like tuple, which includes all its pointers directly), there is special support for storing the __dict__ pointer past the end of the variable-size section (e.g., type("",(tuple,),{}).__dictoffset__ is -8).

The situation with weak references is exactly analogous, except that there is no support for (subclasses of) variable-sized types. A __weakrefoffset__ of 0 (which is conveniently the default for C static variables) indicates no support, since of course the object’s type is known to always be at the beginning of its layout.

Answered By: Davis Herring

It is referenced in PEP 205 here:

Many built-in types will participate in the weak-reference management, and any extension type can elect to do so. The type structure will contain an additional field which provides an offset into the instance structure which contains a list of weak reference structures. If the value of the field is <= 0, the object does not participate. In this case, weakref.ref(), <weakdict>.__setitem__() and .setdefault(), and item assignment will raise TypeError. If the value of the field is > 0, a new weak reference can be generated and added to the list.

And you can see exactly how that works in the source code here.

Check out the other answer for more why it exists.

Answered By: MyNameIsCaleb