@(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