Search code examples
pythonpython-3.xpython-internals

What does `<attribute 'xxx' of 'C' objects>` mean in the output of `C.__dict__`?


>>> class C:
...     pass
... 
>>> C.__dict__
mappingproxy({'__doc__': None, 
'__weakref__': <attribute '__weakref__' of 'C' objects>, 
'__dict__': <attribute '__dict__' of 'C' objects>, 
'__module__': '__main__'})

In <attribute 'xxx' of 'C' objects>,

  • does 'C' objects mean instances of C?
  • does <attribute 'xxx' of 'C' objects> mean xxx is an attribute of instances of C? But it is listed by C.__dict__ as an attribute of C.

Why are some attributes ( e.g. __doc__ and __module__) of C not mentioned with <attribute 'xxx' of 'C' objects>, while others are?


Re: "note: <attribute ..> is basically the repr of these descriptors"

Why is <attribute ..> not shown in the following example?

>>> class md:
...     def __get__(self, obj, owner):
...         return 3
... 

>>> class CC:
...     d=md()
... 
>>> CC.__dict__
mappingproxy({'d': <__main__.md object at 0x7f7387f8c978>, ...})

Solution

  • These are PyGetSetDescrObjects which are computed attributes (descriptors implemented in C) for instances of the class C. Documentation on these is minimal (or I can't seem to find it :-), but, you can take a look at tp_getset in the C-API that talks a bit about these:

    struct PyGetSetDef* PyTypeObject.tp_getset

    An optional pointer to a static NULL-terminated array of PyGetSetDef structures, declaring computed attributes of instances of this type.

    For each entry in the array, an entry is added to the type’s dictionary (see tp_dict below) containing a getset descriptor.

    The objects that don't have <attribute ..> (note: <attribute ..> is basically the repr of these descriptors) are simply not descriptors (__doc__ is usually a string or None if not defined while __module__ holds the name of the module in which the class was defined).


    Re: "note: <attribute ..> is basically the repr of these descriptors"

    Why is <attribute ..> not shown in the following example?

    To address this update that I missed.

    Because that's a descriptor implemented in Python and inherits the default repr from object.

    The repr function of the PyGetSetDescrObjects implemented in C uses a different repr, mainly in order to distinguish them (I'd assume).