什么是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__ ,所以通过类中定义的描述符来访问它。

要理解这一点,你必须阅读描述符协议的文档 。

简短版本:

  1. 对于类A一个实例,访问instance.__dict__A.__dict__['__dict__'] ,这与vars(A)['__dict__']
  2. 对于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