data and non-data descriptors
Descriptors are special class attributes with a custom behavior on attribute get, set, or delete. If an object defines __set__
or __delete__
, it is considered a data descriptor. Descriptors that only define __get__
are called non-data descriptors. The difference is that non-data descriptors are called only if the attribute isn't presented in __dict__
of the instance.
Non-data descriptor:
class D:
def __get__(self, obj, owner):
print('get', obj, owner)
class C:
d = D()
c = C()
c.d
# get <C object at ...> <class 'C'>
# updating __dict__ shadows the descriptor
c.__dict__['d'] = 1
c.d
# 1
Data descriptor:
class D:
def __get__(self, obj, owner):
print('get', obj, owner)
def __set__(self, obj, owner):
print('set', obj, owner)
class C:
d = D()
c = C()
c.d
# get <C object at ...> <class 'C'>
# updating __dict__ doesn't shadow the descriptor
c.__dict__['d'] = 1
c.d
# get <C object at ...> <class 'C'>