Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python __dict__

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?

like image 769
max fraguas Avatar asked Dec 29 '17 22:12

max fraguas


1 Answers

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).

like image 197
Martijn Pieters Avatar answered Sep 19 '22 16:09

Martijn Pieters