Python:使用相同的装饰器装饰__call__和普通函数?

时间:2012-03-12 13:24:17

标签: python decorator

在Python 2.6-2.7中是否可以使用相同的装饰器执行以下任务:

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

@wrap_me
def simple_function(a1, a2):
    pass

ComplextCallableObject.__call__simple_function都有相同的参数,但__call__对第一个参数也有self。在wrap_me装饰器中,我需要访问被包装的函数args。

3 个答案:

答案 0 :(得分:2)

不幸的是,在定义时(本例中为类块),除了命名约定外,代码无法告诉函数如何使用。稍微修改你的例子:

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

@wrap_me
def simple_function(tgt, a1, a2):
    pass

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

在这种情况下,simple_function正在实现一个采用目标和两个参数的函数,一个采用两个参数的实例方法,一个采用两个参数的类方法,一个采用目标和两个参数的静态方法。但是这些用法在定义函数之后才会被绑定。 staticmethodclassmethod都返回不同的对象类型,因此如果需要,您可以区分它们。

如果您确实想使用约定,可以检查函数的第一个参数名称,看它是否为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

答案 1 :(得分:0)

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

当然,如果在类方法上调用self,则需要修改返回的函数以获取wrap_me参数。

顺便说一下,假设你实际上没有在你正在装饰的函数中使用self,它应该是一个静态的方法。

答案 2 :(得分:0)

这可能相当愚蠢,但也可能适用于最简单的情况:

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