Перш за все 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']запитання;) Я себе