Search the object's class and superclasses in method resolution order for the descriptor object:
def find_descriptor(instance, attrname):
'''Find the descriptor handling a given attribute, if any.
If the attribute named attrname of the given instance is handled by a
descriptor, this will return the descriptor object handling the attribute.
Otherwise, it will return None.
'''
def hasspecialmethod(obj, name):
return any(name in klass.__dict__ for klass in type(obj).__mro__)
for klass in type(instance).__mro__:
if attrname in klass.__dict__:
descriptor = klass.__dict__[attrname]
if not (hasspecialmethod(descriptor, '__get__') or
hasspecialmethod(descriptor, '__set__') or
hasspecialmethod(descriptor, '__delete__')):
# Attribute isn't a descriptor
return None
if (attrname in instance.__dict__ and
not hasspecialmethod(descriptor, '__set__') and
not hasspecialmethod(descriptor, '__delete__')):
# Would be handled by the descriptor, but the descriptor isn't
# a data descriptor and the object has a dict entry overriding
# it.
return None
return descriptor
return None