Search code examples
pythonintrospectionpython-decorators

Introspect class property to see if it is decorated, without accessing property value


Here is a simplified version of what I am dealing with:

def mydecorator(prop):
    def wrapper(self_arg):
        return prop(self_arg) + 'bar'
    return wrapper

class Foo(object):

    def __init__(self):
        self.value = 'foo'

    @property
    @mydecorator
    def foo(self):
        return self.value

    @property
    def doesnt_have_my_decorator(self):
        return 'something that requires a lot of computation'

f = Foo()

print f.foo # prints 'foobar'

Now what I would like to be able to do, is introspect f.foo, without actually accessing its value, and check if it is decorated with @mydecorator. Is this possible?

The use case is to be able whitelist a property as "safe" in a certain context, without actually accessing it's value in case it is "unsafe".

I have seen this great post, but it seems like that method requires foo to have already been accessed.

I have found that I can see that it is a property with:

f.__class__.__dict__['foo'].__class__

but I haven't been able to find any references to mydecorator. Since it's Python, I am sure there is a way, but I haven't been able to figure it out so far...


Solution

  • In Python a decorator is merely a shortened syntax. E.g.:

    @property
    @mydecorator
    def foo(self):
        return self.value
    

    is exactly the same as this:

    def foo(self):
        return self.value
    
    foo = property (mydecorator (foo))
    

    Since your decorator doesn't leave any detectable trace on its return value, it is not possible to determine if it was applied. You could instead rewrite to e.g.:

    def mydecorator(prop):
        def wrapper(self_arg):
            return prop(self_arg) + 'bar'
        wrapper._mydecorator = True
        return wrapper
    

    and then use this expression to test it:

    hasattr (type (f).foo.fget, '_mydecorator')