I've read some blogs and docs that when access an instance attribute obj.a:
- try accessing data descriptor (named
a) in current class__dict__and base class __dict__ - find
ainobj.__dict__ - find non-data descriptor (named
a) in current class__dict__and base class__dict__ - find attribute (named
a) in current class__dict__and base class__dict__ - call
__getattr__if any - raise
AttributeError
But I found that this searching rule does not match the behavior of below codes:
class ADesc(object):
def __init__(self, name):
self._name = name
def __get__(self, obj, objclass):
print('get.....')
return self._name + ' ' + str(obj) + ' ' + str(objclass)
def __set__(self, obj, value):
print('set.....')
self._name = value
class A(object):
dd_1 = ADesc('dd_1 in A')
class B(A):
dd_1 = 'dd_1 in B'
if __name__ == '__main__':
print(A.__dict__)
# {'dd_1': <__main__.ADesc object at 0x10ed0d050>, '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
print(B.__dict__)
# {'dd_1': 'dd_1 in B', '__module__': '__main__', '__doc__': None}
b = B()
print(b.dd_1) # dd_1 in B
I think the last print(b.dd_1) will invoke the __get__ in ADesc, because according to the 1st rule, __dict__ of base class A contains the attribute dd_1 that we're accessing, so that data descriptor should be called. So is the above access rule wrong or any other magic involved here ?