[英]What is the __dict__.__dict__ attribute of a Python class?
>>> 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?
If I do A.something = 10
, this goes into A.__dict__
.如果我做
A.something = 10
,这会进入A.__dict__
。 What is this <attribute '__dict__' of 'A' objects>
found in A.__dict__.__dict__
, and when does it contain something?这是什么
<attribute '__dict__' of 'A' objects>
中发现A.__dict__.__dict__
,当它包含的东西吗?
First of all A.__dict__.__dict__
is different from A.__dict__['__dict__']
.首先,
A.__dict__.__dict__
不同于A.__dict__['__dict__']
。 The former doesn't exist and the latter is the __dict__
attribute that the instances of the class would have.前者不存在,后者是类的实例将具有的
__dict__
属性。 It's a data descriptor object that returns the internal dictionary of attributes for the specific instance.它是一个数据描述符对象,它返回特定实例的内部属性字典。 In short, the
__dict__
attribute of an object can't be stored in object's __dict__
, so it's accessed through a descriptor defined in the class.简而言之,对象的
__dict__
属性不能存储在对象的__dict__
,因此它是通过类中定义的描述符访问的。
To understand this, you'd have to read the documentation of the descriptor protocol .要理解这一点,您必须阅读描述符协议的文档。
The short version:简短版本:
a
of a class A
, access to a.__dict__
is provided by A.__dict__['__dict__']
which is the same as vars(A)['__dict__']
.A
的实例a
,对a.__dict__
访问由A.__dict__['__dict__']
,这与vars(A)['__dict__']
。A
, access to A.__dict__
is provided by type.__dict__['__dict__']
(in theory) which is the same as vars(type)['__dict__']
.A
,访问A.__dict__
由type.__dict__['__dict__']
(理论上)提供,这与vars(type)['__dict__']
。 The long version:长版:
Both classes and objects provide access to attributes both through the attribute operator (implemented via the class or metaclass's __getattribute__
), and the __dict__
attribute/protocol which is used by vars(ob)
.类和对象都通过属性运算符(通过类或元类的
__getattribute__
)和vars(ob)
使用的__dict__
属性/协议提供对属性的访问。
For normal objects, the __dict__
object creates a separate dict
object, which stores the attributes, and __getattribute__
first tries to access it and get the attributes from there (before attempting to look for the attribute in the class by utilizing the descriptor protocol, and before calling __getattr__
).对于普通对象,
__dict__
对象创建一个单独的dict
对象,用于存储属性,而__getattribute__
首先尝试访问它并从那里获取属性(在尝试使用描述符协议在类中查找属性之前,以及之前调用__getattr__
)。 The __dict__
descriptor on the class implements the access to this dictionary.类上的
__dict__
描述符实现了对这个字典的访问。
a.name
is equivalent to trying those in order: type(a).__dict__['name'].__get__(a, type(a))
(only if type(a).__dict__['name']
is a data descriptor), a.__dict__['name']
, type(a).__dict__['name'].__get__(a, type(a))
, type(a).__dict__['name']
. a.name
相当于按顺序尝试: type(a).__dict__['name'].__get__(a, type(a))
(仅当type(a).__dict__['name']
是数据描述符时), a.__dict__['name']
, type(a).__dict__['name'].__get__(a, type(a))
, type(a).__dict__['name']
。a.__dict__
does the same but skips the second step for obvious reasons. a.__dict__
做同样的a.__dict__
,但由于显而易见的原因跳过了第二步。 As it's impossible for the __dict__
of an instance to be stored in itself, it's accessed through the descriptor protocol directly instead and is stored in a special field in the instance.由于实例的
__dict__
不可能存储在自身中,因此直接通过描述符协议访问它并存储在实例的特殊字段中。
A similar scenario is true for classes, although their __dict__
is a special proxy object that pretends to be a dictionary (but might not be internally), and doesn't allow you to change it or replace it with another one.类也有类似的情况,尽管它们的
__dict__
是一个特殊的代理对象,它伪装成一个字典(但可能不是内部的),并且不允许您更改它或用另一个替换它。 This proxy allows you, among all else, to access the attributes of a class that are specific to it, and not defined in one of its bases.除其他外,此代理允许您访问特定于它的类的属性,而不是在其基类之一中定义。
By default, a vars(cls)
of an empty class carries three descriptors: __dict__
for storing the attributes of the instances, __weakref__
which is used internally by weakref
, and __doc__
the docstring of the class.缺省情况下,
vars(cls)
一个空类的承载三个描述符: __dict__
用于存储实例的属性, __weakref__
其通过内部使用weakref
,和__doc__
类的文档字符串。 The first two might be gone if you define __slots__
.如果您定义
__slots__
,前两个可能会消失。 Then you wouldn't have __dict__
and __weakref__
attributes, but instead you'd have a single class attribute for each slot.那么你不会有
__dict__
和__weakref__
属性,而是每个插槽都有一个类属性。 The attributes of the instance then wouldn't be stored in a dictionary, and access to them will be provided by the respective descriptors in the class.实例的属性不会存储在字典中,并且对它们的访问将由类中的相应描述符提供。
And lastly, the inconsistency that A.__dict__
is different from A.__dict__['__dict__']
is because the attribute __dict__
is, by exception, never looked up in vars(A)
, so what is true for it isn't true for practically any other attribute you'd use.最后,
A.__dict__
与A.__dict__['__dict__']
的不一致是因为属性__dict__
例外地从未在vars(A)
查找过,所以对它来说是真的几乎任何你会使用的其他属性。 For example, A.__weakref__
is the same thing as A.__dict__['__weakref__']
.例如,
A.__weakref__
与A.__dict__['__weakref__']
。 If this inconsistency didn't exist, using A.__dict__
would not work, and you'd have to always use vars(A)
instead.如果这种不一致不存在,则使用
A.__dict__
将不起作用,您必须始终使用vars(A)
代替。
You can try the following simple example to understand more of this:您可以尝试以下简单示例来了解更多信息:
>>> 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
From the above example, it seems that instance attributes are stored by their class, and class attributes are stored by their metaclass.从上面的例子来看,实例属性是由它们的类存储的,而类属性是由它们的元类存储的。 This is also validated by:
这也得到了验证:
>>> a.__dict__ == A.__getattribute__(a, '__dict__')
True
>>> A.__dict__ == type.__getattribute__(A, '__dict__')
True
Since A.__dict__
is a dictionary storing A
attributes, A.__dict__['__dict__']
is the direct reference to that same A.__dict__
attribute. 由于
A.__dict__
是存储A
属性的字典,因此A.__dict__['__dict__']
是对该同一A.__dict__
属性的直接引用。
A.__dict__
contains a (kind-of) reference to itself. A.__dict__
包含对自身的(一种)引用。 The "kind-of" part is why the expression A.__dict__
returns a dictproxy
instead of a normal dict
. “种类”部分是为什么表达式
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'
Lets do some exploring!让我们做一些探索!
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects>
I wonder what that is?我想知道那是什么?
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
What attributes does a getset_descriptor
object have? getset_descriptor
对象有哪些属性?
>>> type(A.__dict__["__dict__"]).__dict__
<dictproxy object at 0xb7efc4ac>
By making a copy of that dictproxy
we can find some interesting attributes, specifically __objclass__
and __name__
.通过复制该
dictproxy
我们可以找到一些有趣的属性,特别是__objclass__
和__name__
。
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__
(<class '__main__.A'>, '__dict__')
So __objclass__
is a reference to A
and __name__
is just the string '__dict__'
, name of an attribute perhaps?所以
__objclass__
是对A
的引用,而__name__
只是字符串'__dict__'
,也许是一个属性的名称?
>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__
True
There we have it!我们有!
A.__dict__['__dict__']
is an object that can refer back to A.__dict__
. A.__dict__['__dict__']
是一个可以引用回A.__dict__
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.