什么是Python类的__dict __.__ dict__属性?
>>> 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__
。 在A.__dict__.__dict__
find<attribute '__dict__' of 'A' objects>
A.__dict__.__dict__
<attribute '__dict__' of 'A' objects>
是什么?它包含什么东西?
首先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__
)和由vars(ob)
使用的__dict__
属性/协议提供对属性的访问。
对于普通的对象, __getattribute__
__dict__
对象创build一个单独的dict
对象,它存储了属性, __getattribute__
首先尝试访问它并从那里获取属性(在尝试使用描述符协议在类中查找属性之前,之前调用__getattr__
)。 类上的__dict__
描述符实现对这个字典的访问。
-
x.name
相当于按顺序尝试:x.__dict__['name']
,type(x).name.__get__(x, type(x))
,type(x).name
-
x.__dict__
做了同样的x.__dict__
,但跳过第一个显而易见的原因
由于instance
的__dict__
不可能存储在实例的__dict__
中,所以直接通过描述符协议访问,并存储在实例中的特殊字段中。
类似的情况也是如此,虽然它们的__dict__
是假装为字典(但可能不是内部的)的特殊代理对象,并且不允许你改变它或用另一个代替它。 这个代理允许你在其他方面访问特定类的属性,而不是在其中的一个基础上定义。
默认情况下,一个空类的vars(cls)
携带三个描述符:用于存储实例属性的__dict__
,由weakref
内部使用的weakref
以及类的文档string。 如果您定义__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__
包含一个(种类)对自身的引用。 “kind-of”部分是为什么expression式A.__dict__
返回一个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
的副本,我们可以find一些有趣的属性,特别是__objclass__
和__name__
。
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__ (<class '__main__.A'>, '__dict__')
所以__objclass__
是对A
的引用, __name__
只是string'__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
从上面的例子来看,类对象的属性似乎是通过它们的类存储的,类的属性是通过它们的类来存储的,它们是元类。 这也通过以下validation:
>>> a.__dict__ == A.__getattribute__(a, '__dict__') True >>> A.__dict__ == type.__getattribute__(A, '__dict__') True