Прежде всего 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']
вопросов;) Я увижу себя