Is it possible to test if object property uses a descriptor?

Question:

I’m not convinced this is possible, but I thought I’d ask as I’m new to Python. Given an object with a property which its value is handled by a descriptor; is it possible to know that the given descriptor type was involved?

Example Descriptor:

class Column(object):
    def __init__(self, label):
        self.label = label

    def __get__(self, obj, owner):
        return obj.__dict__.get(self.label)

    def __set__(self, obj, value):
        obj.__dict__[self.label] = value

Test Object:

class Test(object):
    name = Column("column_name")

    def add(self):
       print self.name.__class__

Executing this:

my_test = Test()
my_test.name = "myname"
my_test.add()  

This gives: <type 'str'> which is the data type of the value “myname”, is it possible to test for isinstance(self.name, Descriptor) – this returns false, but I want it to return true – or something similar?

Edit – Removed bug of old-style class on Test

Asked By: Matt

||

Answers:

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
Answered By: user2357112

Works just great for me too, I am able to not setattr on properties – which was messing up my generic object generator.

Answered By: C-Rock