在python中对参数进行操作的嵌套函数修饰符

在python中对参数进行操作的嵌套函数修饰符,python,decorator,inspect,keyword-argument,Python,Decorator,Inspect,Keyword Argument,我正在编写一个函数装饰器,它将对函数的第一个参数应用转换。如果我只修饰函数一次,效果很好,但是如果我修饰它们两次,就会出错。下面是一些演示问题的代码,这是我正在处理的代码的简化版本。我已经排除了进行转换的代码,以便不分散对问题的注意力 from inspect import getargspec from functools import wraps def dec(id): def _dec(fn): @wraps(fn) def __dec(*arg

我正在编写一个函数装饰器,它将对函数的第一个参数应用转换。如果我只修饰函数一次,效果很好,但是如果我修饰它们两次,就会出错。下面是一些演示问题的代码,这是我正在处理的代码的简化版本。我已经排除了进行转换的代码,以便不分散对问题的注意力

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
这是因为当第二个decorator检查它正在修饰的函数以查找参数名时失败了,因为它正在修饰一个decorator,并且只接受*args和**kwargs

我可以想出一些方法来解决这个问题,这些方法在上面的代码中是可行的,但是如果一个函数是用我的decorator和另一个第三方的decorator装饰的,那么它仍然会中断。有解决这个问题的一般方法吗?还是有更好的方法达到同样的效果

更新:感谢@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)    

更干净,而且有效

问题在于修饰函数的签名不是原始函数的签名(getargspec)。这是非常好的解释,在帮助你们可以解决你们的问题。基本上,您应该使用保留签名的修饰符,以便第二个修饰符看到与第一个相同的签名。

为什么
args[0],*args[1://code>,它与
*args
相同?您试图用此修饰符解决什么问题?据我所知,它的主要目标似乎是确保第一个给定参数(关键字/可选或其他)始终作为“第一个”参数传递给包装函数。另外,
id
参数对decorator的预期意义是什么?它不在任何地方使用。我想对第一个参数应用转换。在上面提供的代码中,我排除了执行转换的代码,以便不分散对问题的注意力。在实际代码中,我希望能够定义许多不同的装饰器,每个装饰器对函数的第一个参数执行不同的转换。我希望能够将这些装饰程序中的多个应用于给定函数,也可能应用于其他第三方装饰程序。这个id只是用来模拟有许多这样的装饰器的模型——如果你喜欢的话,这个id就是要应用的转换的id。太棒了,这正是我想要的。