The attribute __dict__
is supposed to contain user defined attributes. But if we print the __dict__
of an empty class, I would also get:
__module__
__dict__
__weakref__
__doc__
Which are prepopulated by Python in the __dict__
attribute accordingly to the class object type.
Now, __base__
and __class__
are also Python defined attributes of a class object type, but not included in __dict__
.
Is there any rule that specifies which dunder attribute is included in an object __dict__
and which are not?
The attribute
__dict__
is supposed to contain user defined attributes.
No, the __dict__
contains the dynamic attributes of an object. Those are not the only attributes an object can have however, the type of the object is usually also consulted to find attributes.
For example, the methods on a class can be found as attributes on an instance too. Many such attributes are descriptor objects and are bound to the object when looked up. This is the job of the __getattribute__
method all classes inherit from object
; attributes on an object are resolved via type(object).__getattribute__(attribute_name)
, at which point the descriptors on the type as well as attributes directly set on the object (in the __dict__
mapping) are considered.
The __bases__
attribute of a class is provided by the class metatype, which is type()
by default; it is a descriptor:
>>> class Foo:
... pass
...
>>> Foo.__bases__
(<class 'object'>,)
>>> type.__dict__['__bases__']
<attribute '__bases__' of 'type' objects>
>>> type.__dict__['__bases__'].__get__(Foo, type)
(<class 'object'>,)
__dict__
just happens to be a place to store attributes that can have any valid string name. For classes that includes several standard attributes set when the class is created (__module__
and __doc__
), and others that are there as descriptors for instances of a class (__dict__
and __weakref__
). The latter must be added to the class, because a class itself also has those attributes, taken from type
, again as descriptors.
So why is __bases__
a descriptor, but __doc__
is not? You can't set __bases__
to just anything, so the descriptor setter checks for specific conditions and is an opportunity to rebuild internal caches. The Python core developers use descriptors to restrict what can be set, or when setting a value requires additional work (like validation and updating internal structures).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With