Co to jest dict. atrybut dict klasy Pythona?
>>> class A(object): pass
...
>>> A.__dict__
<dictproxy object at 0x173ef30>
>>> A.__dict__.__dict__
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
AttributeError: 'dictproxy' object has no attribute '__dict__'
>>> A.__dict__.copy()
{'__dict__': <attribute '__dict__' of 'A' objects> ... }
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects> # What is this object?
Jeśli to zrobię A.something = 10
, to pójdzie do A.__dict__
. Co? na to <attribute '__dict__' of 'A' objects>
Znalezione w A.__dict__.__dict__
, a kiedy coś zawiera?
4 answers
Po pierwsze {[0] } różni się od A.__dict__['__dict__']
, a pierwszy nie istnieje. Ten ostatni jest atrybutem __dict__
, który miałyby instancje klasy. Jest to obiekt deskryptora, który zwraca wewnętrzny słownik atrybutów dla konkretnej instancji. W skrócie, atrybut __dict__
obiektu nie może być przechowywany w __dict__
obiektu, więc dostęp do niego jest możliwy poprzez deskryptor zdefiniowany w klasie.
Aby to zrozumieć, musisz przeczytać dokumentację deskryptora protokół .
Wersja skrócona:
- dla instancji klasy
A
dostęp doinstance.__dict__
jest zapewniany przezA.__dict__['__dict__']
, który jest taki sam jakvars(A)['__dict__']
. - dla klasy A dostęp do
A.__dict__
zapewniatype.__dict__['__dict__']
(teoretycznie), który jest taki sam jakvars(type)['__dict__']
.
Wersja długa:
Zarówno klasy, jak i Obiekty zapewniają dostęp do atrybutów zarówno za pośrednictwem operatora atrybutów (zaimplementowanego za pomocą klasy lub metaclass __getattribute__
), jak i __dict__
atrybut / protokół używany przez vars(ob)
.
Dla zwykłych obiektów, obiekt __dict__
tworzy oddzielny obiekt dict
, który przechowuje atrybuty, a {[12] } 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, a przed wywołaniem __getattr__
). Deskryptor __dict__
klasy implementuje dostęp do tego słownika.
-
x.name
jest równoznaczne z próbowaniem tych w kolejności:x.__dict__['name']
,type(x).name.__get__(x, type(x))
,type(x).name
-
x.__dict__
robi to samo, ale pomija pierwszą z oczywistych powodów
Ponieważ nie jest możliwe, aby __dict__
z instance
były przechowywane w __dict__
instancji, jest ona dostępna bezpośrednio przez protokół deskryptora i jest przechowywana w specjalnym polu w instancji.
Podobny scenariusz dotyczy klas, chociaż ich {[2] } jest specjalnym obiektem proxy, który udaje słownik (ale może nie być wewnętrznie) i nie pozwala na zmianę lub zastąpienie go innym. Ten serwer proxy umożliwia między innymi dostęp do atrybutów klasy, które są dla niej specyficzne i nie są zdefiniowane w jednej z jej baz.
Domyślnie, vars(cls)
pustej klasy zawiera trzy deskryptory - {[2] } do przechowywania atrybutów instancji, __weakref__
, który jest używany wewnętrznie przez weakref
, oraz docstring klasy. Pierwsze dwa mogą zniknąć, jeśli zdefiniujesz __slots__
. Wtedy nie mielibyście __dict__
i __weakref__
atrybuty, ale zamiast tego miałbyś jeden atrybut klasy dla każdego gniazda. Atrybuty instancji nie będą wówczas przechowywane w słowniku, a dostęp do nich będą zapewniane przez odpowiednie deskryptory w klasie.
I na koniec, niespójność, która A.__dict__
różni się od A.__dict__['__dict__']
, wynika z faktu, że atrybut __dict__
jest, przez wyjątek, nigdy Nie sprawdzany w vars(A)
, więc to, co jest prawdą, nie jest prawdą dla praktycznie każdego innego atrybutu, którego byś użył. Na przykład, A.__weakref__
to to samo co A.__dict__['__weakref__']
. Jeśli ta niespójność nie istnieje, użycie A.__dict__
nie zadziałałoby i zawsze musiałbyś używać vars(A)
zamiast tego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-02 19:34:57
Ponieważ A.__dict__
jest słownikiem przechowującym atrybuty A
, A.__dict__['__dict__']
jest bezpośrednim odniesieniem do tego samego atrybutu A.__dict__
.
A.__dict__
zawiera (swego rodzaju) odniesienie do siebie. Część "rodzajowa" jest powodem, dla którego wyrażenie A.__dict__
zwraca dictproxy
zamiast normalnego dict
.
>>> class B(object):
... "Documentation of B class"
... pass
...
>>> B.__doc__
'Documentation of B class'
>>> B.__dict__
<dictproxy object at 0x00B83590>
>>> B.__dict__['__doc__']
'Documentation of B class'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-02 17:14:36
Zróbmy trochę zwiedzania!
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects>
Ciekawe co to jest?
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
Jakie atrybuty posiada obiekt getset_descriptor
?
>>> type(A.__dict__["__dict__"]).__dict__
<dictproxy object at 0xb7efc4ac>
Wykonując kopię tego dictproxy
możemy znaleźć kilka interesujących atrybutów, w szczególności __objclass__
i __name__
.
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__
(<class '__main__.A'>, '__dict__')
Więc __objclass__
jest odniesieniem do A
i __name__
jest tylko łańcuchem '__dict__'
, nazwa atrybutu może?
>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__
True
Mamy to! A.__dict__['__dict__']
jest obiektem, który może odwoływać się do A.__dict__
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-02 17:38:05
Możesz spróbować poniższego prostego przykładu, aby zrozumieć więcej z tego:
>>> class A(object): pass
...
>>> a = A()
>>> type(A)
<type 'type'>
>>> type(a)
<class '__main__.A'>
>>> type(a.__dict__)
<type 'dict'>
>>> type(A.__dict__)
<type 'dictproxy'>
>>> type(type.__dict__)
<type 'dictproxy'>
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
>>> type(type.__dict__['__dict__'])
<type 'getset_descriptor'>
>>> a.__dict__ == A.__dict__['__dict__'].__get__(a)
True
>>> A.__dict__ == type.__dict__['__dict__'].__get__(A)
True
>>> a.__dict__ == type.__dict__['__dict__'].__get__(A)['__dict__'].__get__(a)
True
Z powyższego przykładu wynika, że atrybuty obiektów klasy są przechowywane przez ich klasę, atrybuty klasy są przechowywane przez ich klasę, które są metaklasami. Jest to również potwierdzone przez:
>>> a.__dict__ == A.__getattribute__(a, '__dict__')
True
>>> A.__dict__ == type.__getattribute__(A, '__dict__')
True
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-06 23:52:27