18 What is the __dict__.__dict__attribute of a Python class

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__']是不一样的。

  1. Foo.__dict__.__dict__ :根本就不存在
  2. Foo.__dict__['__dict__']用来存储Foo实例的__dict__属性
  1. 实例

    实例会创建一个单独的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,证明上述正确
  2. 类,以类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__的情况

默认情况下,一个空的类有三个描述符,

  1. __dict__,存储实例属性;
  2. __weakref__
  3. __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__ of instance 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 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. For example, A.__weakref__ is the same thing as 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.

总结

以类Foo为例,Foo.attrFoo.__dict__['attr']不相等的情况:

  1. Foo.__dict__ != Foo.__dict__['__dict__']

    因为__dict__属性是个例外,Foo.__dict__并没有存储在Foo上,而是存储在type(Foo)上 。

    Foo.__dict__ == type(Foo).__dict__['__dict__'].__get__(Foo)

  2. 如果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.attrFoo.__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

参考网址

  1. http://stackoverflow.com/questions/4877290/what-is-the-dict-dict-attribute-of-a-python-class
  2. https://docs.python.org/2/library/functions.html?highlight=dictproxy
  3. http://stackoverflow.com/questions/25440694/whats-the-purpose-of-dictproxy
  4. http://blog.csdn.net/lis_12/article/details/53453665
  5. http://blog.csdn.net/lis_12/article/details/53511300
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值