Decorator question (how to test if decorated function is in a class)

Martin P. Hellwig martin.hellwig at dcuktec.org
Fri Jun 19 09:04:12 EDT 2009


Hi all,

I have been trying out to wrap my mind around the advantages of 
decorators and thought I found a use in one of my experiments. (see code 
after my sig).

Although it works, I think it should be able to do it better.
My particular problem is that I want to remove an argument (say always 
the first one) when the decorated function is called.

However if the function is defined in a class the first argument is self 
and thus the second argument should be removed.

Since I like to have a more general DRY approach I want to test if the 
decorated function is defined in a class or not thus knowing that the 
first argument is self and must be preserved.

I tried different approaches but all didn't work and looked very 
unpythonic (looking at the attributes, descriptors namespaces, id() of 
the function, the first argument and the decorator itself).

So is there a way to find out if the first argument is 'self' without 
making a false positive if the first argument is a class instance passed 
to a function?

-- 
MPH
http://blog.dcuktec.com
'If consumed, best digested with added seasoning to own preference.'

code:
class Decorator(object):
     "When used as Decorator(argument) returns a decorator"
     def __init__(self, key):
         self.key = key

     def __call__(self, function):
         "Return a decorator"
         def decorator(*arg_tuple, **arg_dict):
             "The decorator test if the arguments contain a valid key"
             if arg_tuple[0] == self.key:
                 # This means it is a simple function, so check and strip it
                 arg_list = arg_tuple[1::]
                 return(function(*arg_list, **arg_dict))
             elif arg_tuple[1] == self.key:
                 # This means it is a class method, check it,
                 # strip (but retain self)
                 arg_list = arg_tuple
                 arg_list = arg_list[0:1] + arg_list[2::]
                 return(function(*arg_list, **arg_dict))
             else:
                 # The key was invalid
                 return('invalid')

         return(decorator)


class Test(object):
     @Decorator('key')
     def test(self, data):
         return(data)

     @Decorator('key')
     def function_2(self, data):
         return(data)

     @Decorator('key')
     def function_3(self, data):
         return(data)


@Decorator('key')
def test_f(data):
     return(data)

# Test starts here
test_c = Test()
print(test_c.test('key', 'data'))
print(test_f('key', 'data'))
print(test_c.test('invalid', 'data'))
print(test_f('invalid', 'data'))



More information about the Python-list mailing list