>>> 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__
。What is this <attribute '__dict__' of 'A' objects>
A.__dict__.__dict__
in A.__dict__.__dict__
?它什么时候包含某些东西?
发布于 2011-02-03 01:26:03
首先,A.__dict__.__dict__
不同于A.__dict__['__dict__']
。前者不存在,后者是类的实例将具有的__dict__
属性。它是一个数据描述符对象,返回特定实例的内部属性字典。简而言之,对象的__dict__
属性不能存储在对象的__dict__
中,因此可以通过类中定义的描述符来访问它。
要理解这一点,您必须阅读documentation of the descriptor protocol。
简短的版本如下:
a
的实例A
,对a.__dict__
的访问由与vars(A)['__dict__']
.A
相同的A.__dict__['__dict__']
提供,对A.__dict__
的访问(理论上)由与vars(type)['__dict__']
.相同的type.__dict__['__dict__']
提供
长版本:
类和对象都通过属性操作符(通过类或元类的__getattribute__
实现)和vars(ob)
使用的__dict__
属性/协议提供对属性的访问。
对于普通对象,__dict__
对象创建一个单独的dict
对象,该对象存储属性,__getattribute__
首先尝试访问该对象并从中获取属性(在尝试利用描述符协议在类中查找属性之前,以及在调用__getattr__
之前)。类上的__dict__
描述符实现了对此字典的访问。
a.name
等同于按顺序尝试:type(a).__dict__['name']
.a.__dict__
(仅当type(a).__dict__['name']
是数据描述符时)、type(a).__dict__['name'].__get__(a, type(a))
、type(a).__dict__['name'].__get__(a, type(a))
、type(a).__dict__['name'].__get__(a, type(a))
执行相同的操作,但由于显而易见的原因跳过了第二步。由于实例的描述符不可能存储在自身中,因此需要通过__dict__
协议直接访问,并将其存储在实例中的一个特殊字段中。
类似的情况也适用于类,尽管它们的__dict__
是一个特殊的代理对象,它伪装成一个字典(但可能不在内部),并且不允许您更改它或用另一个字典替换它。此代理允许您访问特定于它的类的属性,而不是在它的某个基类中定义的属性。
默认情况下,空类的vars(cls)
包含三个描述符:用于存储实例属性的__dict__
、供weakref
内部使用的__weakref__
和类的文档字符串__doc__
。如果您定义__slots__
,前两个可能会消失。那么您就不会有__dict__
和__weakref__
属性,而是每个插槽都有一个单独的class属性。这样,实例的属性就不会存储在字典中,对它们的访问将由类中相应的描述符提供。
最后,A.__dict__
不同于A.__dict__['__dict__']
的不一致之处在于,属性__dict__
在vars(A)
中是例外的,所以它适用的条件实际上并不适用于您要使用的任何其他属性。例如,A.__weakref__
和A.__dict__['__weakref__']
是一样的。如果不存在这种不一致,使用A.__dict__
将不起作用,您必须始终使用vars(A)
。
发布于 2016-06-07 07:52:28
您可以尝试下面的简单示例来了解更多内容:
>>> 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
发布于 2011-02-03 01:38:05
让我们来探索一下吧!
>>> 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__
的对象。
https://stackoverflow.com/questions/4877290
复制相似问题