Przede wszystkim A.__dict__.__dict__
jest inny A.__dict__['__dict__']
, a tego pierwszego nie ma. Ten ostatni jest __dict__
atrybutem, który miałyby wystąpienia klasy. Jest to obiekt deskryptora, który zwraca wewnętrzny słownik atrybutów dla określonej instancji. Krótko mówiąc, __dict__
atrybut obiektu nie może być przechowywany w obiekcie __dict__
, więc jest dostępny za pośrednictwem deskryptora zdefiniowanego w klasie.
Aby to zrozumieć, musiałbyś przeczytać dokumentację protokołu deskryptora .
Krótka wersja:
- W przypadku klasy
A
, dostęp instance.__dict__
jest zapewniany przez A.__dict__['__dict__']
to samo, co vars(A)['__dict__']
.
- Dla klasy A dostęp
A.__dict__
zapewnia type.__dict__['__dict__']
(w teorii) to samo, co vars(type)['__dict__']
.
Wersja długa:
Zarówno klasy, jak i obiekty zapewniają dostęp do atrybutów zarówno za pośrednictwem operatora atrybutu (zaimplementowanego za pośrednictwem klasy lub metaklasy __getattribute__
), jak i __dict__
atrybutu / protokołu, który jest używany przez vars(ob)
.
W przypadku normalnych obiektów __dict__
obiekt tworzy oddzielny dict
obiekt, który przechowuje atrybuty i __getattribute__
najpierw próbuje uzyskać do niego dostęp i stamtąd pobrać atrybuty (przed próbą wyszukania atrybutu w klasie przy użyciu protokołu deskryptora i przed wywołaniem __getattr__
). __dict__
Deskryptor od klasy implementuje dostęp do tego słownika.
x.name
jest równoważne próbuje te w kolejności: x.__dict__['name']
, type(x).name.__get__(x, type(x))
,type(x).name
x.__dict__
robi to samo, ale pomija pierwszy z oczywistych powodów
Jak to jest możliwe, aby __dict__
z instance
być przechowywane w __dict__
instancji, jest on dostępny za pośrednictwem protokołu deskryptora zamiast bezpośrednio, i jest przechowywany w specjalnym polu w instancji.
Podobny scenariusz jest prawdziwy dla klas, chociaż ich __dict__
jest specjalnym obiektem proxy, który udaje słownik (ale może nie być wewnętrznie) i nie pozwala na jego zmianę lub zastąpienie innym. To proxy umożliwia między innymi dostęp do atrybutów klasy, które są dla niej specyficzne i nie są zdefiniowane w żadnej z jej baz.
Domyślnie vars(cls)
klasa pustej zawiera trzy deskryptory - __dict__
do przechowywania atrybutów instancji, __weakref__
które są używane wewnętrznie przez weakref
klasę, oraz do jej opisu. Pierwsze dwa mogą zniknąć, jeśli zdefiniujesz __slots__
. Wtedy nie miałbyś atrybutów __dict__
i __weakref__
, ale zamiast tego miałbyś jeden atrybut klasy dla każdego gniazda. Atrybuty instancji nie byłyby wtedy przechowywane w słowniku, a dostęp do nich zapewnią odpowiednie deskryptory w klasie.
I wreszcie, niespójność, która A.__dict__
różni się od A.__dict__['__dict__']
tego, że atrybut __dict__
jest wyjątkowy, nigdy nie jest sprawdzany vars(A)
, więc to, co jest prawdą, nie jest prawdą dla praktycznie każdego innego atrybutu, którego użyjesz. Na przykład A.__weakref__
to to samo, co A.__dict__['__weakref__']
. Gdyby ta niespójność nie istniała, używanie A.__dict__
nie działałoby i musiałbyś zawsze używać vars(A)
zamiast tego.
ive
. Przynajmniej sprawiłoby to więcejA.__dict__['ive']
pytań;) zobaczę się poza