Прежде всего A.__dict__.__dict__отличается от A.__dict__['__dict__'], а первого не существует. Последний - это __dict__атрибут, который будут иметь экземпляры класса. Это объект-дескриптор, который возвращает внутренний словарь атрибутов для конкретного экземпляра. Короче говоря, __dict__атрибут объекта не может быть сохранен в объекте __dict__, поэтому доступ к нему осуществляется через дескриптор, определенный в классе.
Чтобы понять это, вам нужно прочитать документацию по протоколу дескриптора .
Краткая версия:
- Для экземпляра класса
A, доступ к instance.__dict__обеспечивается A.__dict__['__dict__']который является таким же , как vars(A)['__dict__'].
- Для класса A доступ к
A.__dict__предоставляется type.__dict__['__dict__'](теоретически), который совпадает с vars(type)['__dict__'].
Полная версия:
И классы, и объекты предоставляют доступ к атрибутам как через оператор атрибута (реализованный через класс или метакласс __getattribute__), так и через __dict__атрибут / протокол, который используется vars(ob).
Для обычных объектов __dict__объект создает отдельный dictобъект, в котором хранятся атрибуты, и __getattribute__сначала пытается получить к нему доступ и получить оттуда атрибуты (перед попыткой поиска атрибута в классе с использованием протокола дескриптора и перед вызовом __getattr__). __dict__Дескриптор на класс реализует доступ к этому словарю.
x.nameравносильна попытке тех , в следующем порядке: x.__dict__['name'], type(x).name.__get__(x, type(x)),type(x).name
x.__dict__ делает то же самое, но пропускает первый по понятным причинам
Как это невозможно для __dict__из instanceхранить в __dict__экземпляре, он доступен через протокол дескриптора непосредственно вместо этого, и хранится в специальном поле в экземпляре.
Аналогичный сценарий верен для классов, хотя они __dict__представляют собой специальный прокси-объект, который притворяется словарем (но может не быть внутренним) и не позволяет вам изменять его или заменять другим. Этот прокси позволяет вам, помимо всего прочего, получить доступ к атрибутам класса, которые являются специфическими для него и не определены ни в одной из его баз.
По умолчанию a vars(cls)пустого класса содержит три дескриптора - __dict__для хранения атрибутов экземпляров, __weakref__которые используются внутри weakref, и строки документации класса. Первые два могут исчезнуть, если вы определитесь __slots__. Тогда у вас не будет __dict__и __weakref__атрибуты, но вместо этого вы бы один атрибут класса для каждого слота. Тогда атрибуты экземпляра не будут храниться в словаре, и доступ к ним будет обеспечиваться соответствующими дескрипторами в классе.
И, наконец, несогласованность, которая A.__dict__отличается от, A.__dict__['__dict__']заключается в том, что атрибут __dict__, в порядке исключения, никогда не просматривается vars(A), поэтому то, что верно для него, неверно практически для любого другого атрибута, который вы бы использовали. Например, A.__weakref__это то же самое, что и A.__dict__['__weakref__']. Если бы этой несоответствия не было, использование A.__dict__не сработало бы, и вам пришлось бы всегда использовать vars(A)вместо него.
ive. По крайней мере, это вызвало бы еще большеA.__dict__['ive']вопросов;) Я увижу себя