Python __dict__

Атрибут __dict__ должен содержать определенные пользователем атрибуты. Но если мы напечатаем __dict__ пустого класса, я также получу:

__module__
__dict__ 
__weakref__
__doc__

Которые предварительно заполняются Python в атрибуте __dict__ в соответствии с типом объекта класса.

Теперь __base__ и __class__ также являются определенными в Python атрибутами типа объекта класса, но не включены в __dict__.

Существует ли какое-либо правило, определяющее, какой атрибут dunder включается в объект __dict__, а какой нет?


person max fraguas    schedule 29.12.2017    source источник


Ответы (1)


Атрибут __dict__ должен содержать определенные пользователем атрибуты.

Нет, __dict__ содержит динамические атрибуты объекта. Однако это не единственные атрибуты, которые может иметь объект. Обычно для поиска атрибутов также используется тип объекта.

Например, методы класса можно найти как атрибуты экземпляра. Многие такие атрибуты являются объектами-дескрипторами и привязаны к объект при взгляде вверх. Это работа метода __getattribute__, который все классы наследуют от object; атрибуты объекта разрешаются через type(object).__getattribute__(attribute_name), после чего учитываются дескрипторы типа, а также атрибуты, непосредственно установленные для объекта (в сопоставлении __dict__).

Атрибут __bases__ класса предоставляется метатипом класса, который по умолчанию равен type(); это дескриптор:

>>> class Foo:
...     pass
...
>>> Foo.__bases__
(<class 'object'>,)
>>> type.__dict__['__bases__']
<attribute '__bases__' of 'type' objects>
>>> type.__dict__['__bases__'].__get__(Foo, type)
(<class 'object'>,)

__dict__ просто место для хранения атрибутов, которые могут иметь любое допустимое строковое имя. Для классов, которые включают в себя несколько стандартных атрибутов, установленных при создании класса (__module__ и __doc__), а также другие атрибуты, присутствующие в качестве дескрипторов экземпляров класса (__dict__ и __weakref__). Последний должен быть добавлен в класс, потому что сам класс также имеет эти атрибуты, взятые из type, опять же в качестве дескрипторов.

Так почему же __bases__ — это дескриптор, а __doc__ — нет? Вы не можете установить __bases__ на что угодно, поэтому установщик дескриптора проверяет определенные условия и дает возможность перестроить внутренние кэши. Разработчики ядра Python используют дескрипторы, чтобы ограничить то, что может быть установлено, или когда установка значения требует дополнительной работы (например, проверки и обновления внутренних структур).

person Martijn Pieters    schedule 29.12.2017
comment
Большое спасибо @Martijn за ваш ответ. Это было очень полезно. - person max fraguas; 30.12.2017
comment
__bases__ доступен для записи (по крайней мере, для тех же классов, где __doc__ доступен для записи). Это дескриптор, потому что его установка требует дополнительной обработки, которая не подходила бы для type.__setattr__, и потому что для реализации более удобно (и эффективнее) хранить базовые данные в выделенном слоте в структуре памяти класса, а не помещать их в связанном дикт. - person user2357112 supports Monica; 30.12.2017