我正在编写一个函数装饰器,它将对函数的第一个参数应用转换。如果我只装饰我的功能一次,它工作正常,但如果我装饰它们两次,我会得到一个错误。下面是一些演示问题的代码,它是我正在处理的代码的简化版本。我已经排除了进行转换的代码,以免分散注意力
from inspect import getargspec
from functools import wraps
def dec(id):
def _dec(fn):
@wraps(fn)
def __dec(*args, **kwargs):
if len(args):
return fn(args[0], *args[1:], **kwargs)
else:
first_arg = getargspec(fn).args[0]
new_kwargs = kwargs.copy()
del new_kwargs[first_arg]
return fn(kwargs[first_arg], **new_kwargs)
return __dec
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
当我运行上面的代码时,我得到以下输出:
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
IndexError: list index out of range
这是因为当第二个装饰器检查它正在装饰的函数以查找参数名称时,它失败了,因为它正在装饰一个装饰器并且只需要 *args 和 **kwargs。
我可以想出解决问题的方法,这些方法可以在上面的代码中使用,但如果一个函数用我的装饰器和来自第 3 方的另一个装饰器装饰,它仍然会中断。有没有解决这个问题的通用方法?还是有更好的方法来达到相同的结果?
更新:感谢@Hernan 指出装饰器模块。正好解决了这个问题。现在我的代码如下所示:
from decorator import decorator
def dec(id):
@decorator
def _dec(fn, *args, **kwargs):
return fn(args[0], *args[1:], **kwargs)
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
更清洁,它的工作原理!