什么是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