Python Attribute Access Order

@(Python)

data descriptor case

data descriptor is defined as having both _get_ and _set_ method

class descriptor(object):
    def __get__(self, obj, type=None):
        print('descriptor-get')
    def __set__(self, obj, value):
        print('descriptor-set')
class A(object):
    x = descriptor()
    def __getattr__(self, name):
        print('A-getattr')
    
a = A()

a.__dict__ # empty instance dictionary
-> {}

A.__dict__ # type dictionary has attribute 'x'
-> dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>,
            '__doc__': None,
            '__getattr__': <function __main__.__getattr__>,
            '__module__': '__main__',
            '__weakref__': <attribute '__weakref__' of 'A' objects>,
            'x': <__main__.descriptor at 0x1065fec10>})

a.x # data descriptor takes precedence
-> descriptor-get

A.x # visit descriptor from type or class
-> descriptor-get

del A.__dict__['x'] # disallow to del attributes in type dictionary
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-52-bc9fd0bf9cec> in <module>()
----> 1 del A.__dict__['x']

TypeError: 'dictproxy' object does not support item deletion

non-data descriptor case

non-data descriptor is defined as only having _get_ method

class descriptor(object):
    def __get__(self, obj, type=None):
        print('descriptor-get')
class A(object):
    x = descriptor()
    def __getattr__(self, name):
        print('A-getattr')
    
a = A()

a.x # non-data descriptor is used because there is no such attribute in instance dictionary
-> descriptor-get

A.x
-> descriptor-get

A.__dict__
-> dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>,
            '__doc__': None,
            '__getattr__': <function __main__.__getattr__>,
            '__module__': '__main__',
            '__weakref__': <attribute '__weakref__' of 'A' objects>,
            'x': <__main__.descriptor at 0x1066008d0>})

a.__dict__['x'] = 2 # set 'x' attribute into instance dictionary or a.x=2

a.x # instance dictionary takes precedence
-> 2

A.x
-> descriptor-get

_getattr_ as backup

class A(object):
    def __getattr__(self, name):
        print('A-getattr')
    
a = A()

a.x # __getattr__ is called when there is no 'x' in data descriptor, instance dictionary and non-data descriptor.
-> A-getattr
 
A.__dict__['x'] = 1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-66-72c8240053eb> in <module>()
----> 1 A.__dict__['x'] = 1

TypeError: 'dictproxy' object does not support item assignment


a.__dict__['x'] = 1 # or 

a.x # instance dictionary takes precedence to __getattr__
-> 1

del a.x

a.x
-> A-getattr

A.x = descriptor() # assign a non-data descriptor into type dictionary 

A.x
-> descriptor-get

a.x # instance dictionary takes precedence to such non-data descriptor
-> 1

del a.x

a.x # non-data descriptor takes precedence to __getattr__
-> descriptor-get
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容