>>> 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?
내가 그렇게 A.something = 10
하면 A.__dict__
. 무엇 이다 이 <attribute '__dict__' of 'A' objects>
에서 발견이 A.__dict__.__dict__
뭔가를 포함 않을 때, 그리고?
답변
우선는와 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__
of instance
를 __dict__
인스턴스에 저장할 수 없기 때문에 설명자 프로토콜을 통해 직접 액세스하고 인스턴스의 특수 필드에 저장합니다.
클래스의 경우에도 유사한 시나리오가 적용되지만 __dict__
, 사전 인 척하는 특수 프록시 개체 (내부적으로는 아닐 수 있음)이며이를 변경하거나 다른 것으로 대체 할 수 없습니다. 이 프록시를 사용하면 무엇보다도 자신에게 고유하고 기본 중 하나에 정의되지 않은 클래스의 속성에 액세스 할 수 있습니다.
기본적으로 vars(cls)
비어있는 클래스의 a 는에서 내부적으로 사용 __dict__
하는 인스턴스의 속성 과 클래스의 독 스트링 을 저장하기위한 세 개의 설명자를 전달 합니다. 정의하면 처음 두 개가 사라질 수 있습니다 . 그러면 및 속성이 없지만 대신 각 슬롯에 대해 단일 클래스 속성이 있습니다. 그러면 인스턴스의 속성이 사전에 저장되지 않고 클래스의 각 설명자가 액세스 할 수 있습니다.__weakref__
weakref
__slots__
__dict__
__weakref__
그리고 마지막으로, 불일치 A.__dict__
다른는 A.__dict__['__dict__']
속성이 있기 때문입니다 __dict__
입니다, 예외로, 결코 에서 보지 않았다 vars(A)
그래서 무엇 마찬가지입니다 것은 당신이 사용하는 거라고 거의 모든 다른 속성에 대한 사실이 아니다. 예를 들어 A.__weakref__
는 A.__dict__['__weakref__']
. 이 불일치가 존재하지 않으면 사용 A.__dict__
이 작동하지 않으며 항상 vars(A)
대신 사용해야 합니다.
답변
속성을 A.__dict__
저장하는 딕셔너리 이므로 동일한 속성에 대한 직접 참조 입니다.A
A.__dict__['__dict__']
A.__dict__
A.__dict__
자신에 대한 (종류의) 참조를 포함합니다. “종류”부분은 표현식 이 일반 대신 A.__dict__
a dictproxy
를 반환하는 이유 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'
답변
탐험을 좀 해보자!
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects>
그게 뭔지 궁금 해요?
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
getset_descriptor
개체에는 어떤 속성 이 있습니까?
>>> type(A.__dict__["__dict__"]).__dict__
<dictproxy object at 0xb7efc4ac>
그 사본을 만들면 dictproxy
흥미로운 속성, 특히 __objclass__
및 __name__
.
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__
(<class '__main__.A'>, '__dict__')
그래서 __objclass__
에 대한 참조입니다 A
및 __name__
단지 문자열입니다 '__dict__'
아마 속성의 이름을?
>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__
True
거기에 있습니다! A.__dict__['__dict__']
다시 참조 할 수있는 객체입니다.A.__dict__
.
답변
다음과 같은 간단한 예제를 통해 더 많은 것을 이해할 수 있습니다.
>>> 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
위의 예에서 클래스 객체 속성은 클래스별로 저장되고 클래스의 속성은 메타 클래스 인 클래스별로 저장됩니다. 이것은 또한 다음에 의해 검증됩니다.
>>> a.__dict__ == A.__getattribute__(a, '__dict__')
True
>>> A.__dict__ == type.__getattribute__(A, '__dict__')
True