Python: decorate __call__ and normal function with the same decorator?

Is it possible in Python 2.6-2.7 to use the same decorator for the following task:

class ComplextCallableObject(object):
    def __call__(self, a1, a2):

def simple_function(a1, a2):


Both ComplextCallableObject.__call__

and simple_function

have the same arguments, but __call__

also has one self

for the first arg. In the decorator, wrap_me

I need access for the wrapped args functions.


source to share

3 answers

Unfortunately, at the time of definition (a class block in this case), the code cannot determine how the function will be used other than by naming convention. Modify your example a bit:

class ComplextCallableObject(object):
    def __call__(self, a1, a2):
        pass #...

def simple_function(tgt, a1, a2):

ComplextCallableObject.anInstanceMethod = simple_function
ComplextCallableObject.anClassMethod = classmethod(simple_function)
ComplextCallableObject.aStaticMethod = staticmethod(simple_function)


In this case, it simple_function

implements a function that takes a target and two parameters, an instance method that takes two parameters, a class method that takes two parameters, and a static method that takes a target and two parameters. But this usage is not related only after the function is defined. Both staticmethod

and classmethod

return a different type of object, so you can talk about it if needed.

If you want to use a convention, you can check the name of the first argument to the function to see if it is self


def wrap_me(fn):
    names = fn.func_code.co_varnames
    if names and names[0]=='self':
        print 'looks like an instance method'
    else: print 'looks like a function'
    return fn




def wrap_me(*args):
    a1, a2 = args if len(args) == 2 else args[1:]


Of course, you will need to modify the return function to accept an argument self

if wrap_me

called in a class method as well.

By the way, if you are not using self

inside the function you are decorating, it really should be a static method.



This can be pretty silly, but it can work in the simplest case too:

In [1]: def wrap_me(func):
   ...:     def wrapped(*args):
   ...:         print 'arg1 is', args[-2]
   ...:         print 'arg2 is', args[-1]
   ...:         func(*args)
   ...:     return wrapped
In [2]: class ComplexCallableObject(object):
   ...:     @wrap_me
   ...:     def __call__(self, a1, a2):
   ...:         print 'class object called'
In [3]: @wrap_me
   ...: def simple_function(a1, a2):
   ...:     print 'function called'
In [4]: simple_function('A', 'B')
arg1 is A
arg2 is B
function called
In [5]: o = ComplexCallableObject()
In [6]: o('A', 'B')
arg1 is A
arg2 is B
class object called




All Articles