What is the __dict__.__dict__
attribute of a Python class?
转载请标明出处(http://blog.csdn.net/lis_12/article/details/53519060)
problem
class Foo(object):
pass
>>>Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None})
>>>Foo.__dict__.__dict__
AttributeError: 'dictproxy' object has no attribute '__dict__'
>>>Foo.__dict__['__dict__']
<attribute '__dict__' of 'Foo' objects>
Foo.__dict__
里面有'__dict__': <attribute '__dict__' of 'Foo' objects>
属性,用Foo.__dict__.__dict__
访问不到,用Foo.__dict__['__dict__']
可以访问到,为什么呢?
搜索结果:stackoverflow解释链接,本文也是基于stackoverflow的解释,另外本文不考虑没有__dict__
属性的实例。为了更好的理解本文,建议学习描述符…
解释
Foo.__dict__.__dict__
和Foo.__dict__['__dict__']
是不一样的。
Foo.__dict__.__dict__
:根本就不存在Foo.__dict__['__dict__']
:用来存储Foo实例的__dict__
属性。
实例
实例会创建一个单独的dict对象来存储实例的属性,实例的
__dict__
存储在实例对应的类上,即type(实例)上。instance.__dict__
可以从type(instance).__dict__['__dict__']
中获取;因为
type(instance).__dict__['__dict__']
为描述符,所以
instance.__dict__ = type(instance).__dict__['__dict__'].__get__(instance,type(instance))
t = Foo.__dict__['__dict__'] print '__get__' in dir(t) #True,说明Foo.__dict__['__dict__']是描述符 print type(t) #<type 'getset_descriptor'> f = Foo() print type(f.__dict__) #<type 'dict'> d = t.__get__(f,type(f)) #利用描述符对象获取实例的__dict__ print f.__dict__ is d #True,证明上述正确
类,以类Foo为例,
Foo的
__dict__
属性没有存储在Foo上,而是存储在Foo对应的类上,即type(Foo)上。对于type(Foo)来说,Foo为type(Foo)的实例。Foo.__dict__
可以从type(Foo).__dict__['__dict__']
中获取;因为
type(Foo).__dict__['__dict__']
为描述符,所以
Foo.__dict__ = type(Foo).__dict__['__dict__'].__get__(Foo,type(Foo))
t = type(Foo).__dict__['__dict__'] print '__get__' in dir(t) #True,说明type(Foo).__dict__['__dict__']是描述符 print type(t) #<type 'getset_descriptor'> print type(Foo.__dict__) #<type 'dictproxy'>,与实例的__dict__属性不同 d = t.__get__(Foo) print Foo.__dict__ == d #True,值相等 print Foo.__dict__ is d #False,虽然值相等,但地址不同,猜想...d应该是Foo.__dict__的拷贝,知道的大神求指导
类的
__dict__
属性不同于实例的__dict__
属性。类的__dict__
属性是一个特殊代理对象(dictproxy),只不过这个对象伪装成了字典,并且class.__dict__
不允许更改和替换。摘自官网的一句话:new-style classes use a dictproxy to prevent direct dictionary updates.
class A(object): pass print A.__dict__ #{'__dict__': <attribute '__dict__' of 'A' objects>... print type(A.__dict__) #<type 'dictproxy'> #不能重写A.__dict__ A.__dict__ = 1 #AttributeError: attribute '__dict__' of 'type' objects is not writable
实例中不存在__dict__
的情况
默认情况下,一个空的类有三个描述符,
__dict__
,存储实例属性;__weakref__
;__doc__
如果定义了__slots__
,__dict__
和__weakref__
两个属性就没有了,__slots__
中出现的变量名称将会以类属性的形式存在。
class Foo(object):
__slots__ = 'a','b'
f = Foo()
#print f.__dict__ #AttributeError: 'Foo' object has no attribute '__dict__'
print Foo.__dict__ #{'a': <member 'a' of 'Foo' objects>, '__module__': '__main__', 'b': <member 'b' of 'Foo' objects>, '__slots__': ('a', 'b'), '__doc__': None}
__dict__
不存储在实例上的原因
As it’s impossible for the
__dict__
ofinstance
to be stored in__dict__
of the instance, it is accessed through the descriptor protocol directly instead, and is stored in a special field in the instance.原因:
The inconsistency that
A.__dict__
is different fromA.__dict__['__dict__']
is because the attribute__dict__
is, by exception, never looked up invars(A)
, so what is true for it isn’t true for practically any other attribute you’d use. For example,A.__weakref__
is the same thing asA.__dict__['__weakref__']
. If this inconsistency didn’t exist, usingA.__dict__
would not work, and you’d have to always usevars(A)
instead.
总结
以类Foo为例,Foo.attr
与Foo.__dict__['attr']
不相等的情况:
Foo.__dict__ != Foo.__dict__['__dict__']
因为
__dict__
属性是个例外,Foo.__dict__
并没有存储在Foo上,而是存储在type(Foo)
上 。Foo.__dict__ == type(Foo).__dict__['__dict__'].__get__(Foo)
如果attr为自定义的描述符对象,
Foo.attr != Foo.__dict__['attr']
在属性访问时,如果被访问的属性为描述符,会自动调用描述符的
__get__()方法
,所以
Foo.attr == Foo.__dict__['attr'].__get__(None,Foo)
class d(object): def __get__(self,obj,type = None): return 1 class Foo(object): a = d() b = 1 def attr(self): pass '''attr为自定义方法,证明方法为描述符''' print '__get__' in dir(Foo.__dict__['attr']) #True print Foo.attr == Foo.__dict__['attr'] #False print Foo.attr == Foo.__dict__['attr'].__get__(None,Foo)#True '''自定义的描述符''' x = Foo.a y = Foo.__dict__['a'] print x == y #False print x == y.__get__(None,Foo) #True
Foo.attr
与Foo.__dict__['attr']
相等的情况:
Foo.attr
==Foo.__dict__['attr']
,attr不是__dict__
和自定义描述符.
print Foo.b == Foo.__dict__['b'] #True
w = Foo.__dict__['__weakref__']
print '__get__' in dir(Foo.__weakref__) #True
print Foo.__weakref__ == w #True,__weakref__不是自定义描述符
print Foo.__weakref__ == w.__get__(None,Foo) #True
code
class A(object):
pass
a = A()
print 'type(a) = ',type(a) #type(a) = <class '__main__.A'>
print 'type(A) = ',type(A) #type(A) = <type 'type'>
print 'a.__dict__ = ',a.__dict__ #a.__dict__ = {}
print 'A.__dict__ = ',A.__dict__ #{'__dict__': <attribute '__dict__' of 'A' objects>...
#print 'type.__dict__ = ',type.__dict__,'\n'
print 'type(a.__dict__) = ',type(a.__dict__)
print 'type(A.__dict__) = ',type(A.__dict__)
print 'type(type.__dict__) = ',type(type.__dict__),'\n'
'''
result:
type(a.__dict__) = <type 'dict'>
type(A.__dict__) = <type 'dictproxy'>
type(type.__dict__) = <type 'dictproxy'>
'''
print "A.__dict__['__dict__'] = ",A.__dict__['__dict__']
print "type.__dict__['__dict__'] = ",type.__dict__['__dict__'],'\n'
print "type(A.__dict__['__dict__']) = ",type(A.__dict__['__dict__'])
print "type(type.__dict__['__dict__']) = ",type(type.__dict__['__dict__']),'\n'
'''
result:
A.__dict__['__dict__'] = <attribute '__dict__' of 'A' objects>
type.__dict__['__dict__'] = <attribute '__dict__' of 'type' objects>
type(A.__dict__['__dict__']) = <type 'getset_descriptor'>
type(type.__dict__['__dict__']) = <type 'getset_descriptor'>
'''
print a.__dict__ == A.__dict__['__dict__'].__get__(a)
print a.__dict__ == A.__dict__['__dict__'].__get__(a,type(a))
print A.__dict__ == type(A).__getattribute__(A, '__dict__')
print A.__dict__ == type(A).__dict__['__dict__'].__get__(A)
print A.__dict__ == type(A).__dict__['__dict__'].__get__(A,type(A))
print a.__dict__ == A.__getattribute__(a, '__dict__')
print a.__dict__ == type(A).__dict__['__dict__'].__get__(A)['__dict__'].__get__(a)
#上述都为True
参考网址
- http://stackoverflow.com/questions/4877290/what-is-the-dict-dict-attribute-of-a-python-class
- https://docs.python.org/2/library/functions.html?highlight=dictproxy
- http://stackoverflow.com/questions/25440694/whats-the-purpose-of-dictproxy
- http://blog.csdn.net/lis_12/article/details/53453665
- http://blog.csdn.net/lis_12/article/details/53511300