por*_*uod 81 python metaprogramming class magic-methods
>>> 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?
Run Code Online (Sandbox Code Playgroud)
如果我这样做A.something = 10,这就进入了A.__dict__.什么是这个<attribute '__dict__' of 'A' objects>发现A.__dict__.__dict__,当它包含的东西吗?
Ros*_*ron 101
首先A.__dict__.__dict__是不同的A.__dict__['__dict__'],前者不存在.后者是__dict__类的实例所具有的属性.它是一个描述符对象,它返回特定实例的内部属性字典.简而言之,__dict__对象的属性不能存储在对象中__dict__,因此可以通过类中定义的描述符进行访问.
简短版本:
A访问权与其相同.instance.__dict__A.__dict__['__dict__']vars(A)['__dict__']A.__dict__由type.__dict__['__dict__'](理论上)提供,与之相同vars(type)['__dict__'].长版:
类和对象都通过属性运算符(通过类或元类实现__getattribute__)以及使用的__dict__属性/协议提供对属性的访问vars(ob).
对于正常对象,则__dict__对象创建一个单独的dict对象,其存储的属性,并__getattribute__首先尝试从那里访问它,并获得属性(在试图通过利用该描述符协议来寻找在类中的属性之前,并调用之前__getattr__).在__dict__对类描述符实现了上网本字典.
x.name等同于审判那些依次是:x.__dict__['name'],type(x).name.__get__(x, type(x)),type(x).namex.__dict__ 做同样但跳过第一个明显的原因因为它是不可能的__dict__的instance要被存储在__dict__该实例的,它是通过描述符访问协议,而不是直接,并且被存储在一个特殊字段中的实例.
类似的情况对于类来说也是如此,尽管它们__dict__是一个假装成字典的特殊代理对象(但可能不是内部的),并且不允许您更改它或用另一个替换它.此代理允许您访问特定于其中的类的属性,而不是在其中一个基础中定义.
默认情况下,一个vars(cls)空类的一个带有三个描述符 - __dict__用于存储实例的属性,这些属性由__weakref__内部使用weakref,以及类的docstring.如果你定义,前两个可能会消失__slots__.然后,你就不会__dict__和__weakref__属性,而是你必须为每个插槽一个类属性.然后,实例的属性将不存储在字典中,并且将由类中的相应描述符提供对它们的访问.
最后,A.__dict__不同的不一致A.__dict__['__dict__']是因为该属性__dict__是异常的,从不抬头vars(A),所以对于它来说实际上对于你使用的任何其他属性都是如此.例如,A.__weakref__与之相同A.__dict__['__weakref__'].如果不存在这种不一致,则使用A.__dict__不起作用,而您必须始终使用vars(A).
vz0*_*vz0 10
由于A.__dict__是存储A属性的字典,因此A.__dict__['__dict__']是对该相同A.__dict__属性的直接引用.
A.__dict__包含对自身的(种类)引用."kind-of"部分是表达式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'
Run Code Online (Sandbox Code Playgroud)
让我们做一些探索!
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects>
Run Code Online (Sandbox Code Playgroud)
我不知道那是什么?
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
Run Code Online (Sandbox Code Playgroud)
getset_descriptor对象有什么属性?
>>> type(A.__dict__["__dict__"]).__dict__
<dictproxy object at 0xb7efc4ac>
Run Code Online (Sandbox Code Playgroud)
通过使的那一份dictproxy,我们可以发现一些有趣的特性,特别是__objclass__和__name__.
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__
(<class '__main__.A'>, '__dict__')
Run Code Online (Sandbox Code Playgroud)
所以__objclass__是一个参考A,并__name__仅仅是字符串'__dict__',也许是一个属性的名字吗?
>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__
True
Run Code Online (Sandbox Code Playgroud)
我们有它! 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
Run Code Online (Sandbox Code Playgroud)
从上面的例子看,类对象属性似乎是由它们的类存储的,类的属性是由它们的类存储的,它们是元类.这也通过以下方式验证:
>>> a.__dict__ == A.__getattribute__(a, '__dict__')
True
>>> A.__dict__ == type.__getattribute__(A, '__dict__')
True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
77261 次 |
| 最近记录: |