装饰器,允许函数接受任意参数 - python

如何编写装饰器,使装饰后的函数可以接受(并忽略)任意参数?

我有一些这样的功能:

def foo(x):
    return x

def foo2(x, y):
    if bar(y):
        return x
    else:
        return x + 1

def foo3(x, y, z):
    ...

foo()可以仅基于x来计算给定x的返回值,但是foo2()需要另一个参数,而foo3()需要第三个参数。我在其他地方有一种方法,除其他外,该方法根据用户指定的参数调用foo()foo2()等。

现在,该方法只需使用getattr(user_arg)捕获适当的函数,然后使用所有xyz进行调用。为了避免因错误的参数数量而导致TypeError,所有的foo函数都用*args定义,如下所示:

def foo(x, *args):
    return x

但是我只想有一个装饰器,以避免在每个*args函数定义中都包含foo。有没有办法做到这一点?还是可以建议一种更好的方式来组织此代码?

一种方法是编写这样的方法:

if user_arg == 'foo':
    foo(x)
elif user_arg == 'foo2':
    foo2(x, y)
elif user_arg == 'foo3':
    foo3(x, y, z)

但是我真的很想避免这种情况,因为有很多foo函数,并且因为我想可以添加新的foo函数而不必向该方法添加另一个分支。

编辑:澄清一下,不是我需要根据参数数量调用不同的foo函数。调用(用户指定的)哪个foo函数是任意的。

def foo3(x, y, z):
    return x + y + z

def foo4(x, y, z):
    return x + y - z

python大神给出的解决方案

您可以使用inspect.getargspec确定装饰函数采用哪些参数:

import functools
import inspect

def ignore_extra_arguments(func):
    args, varargs, kwvarargs, defaults = inspect.getargspec(func)
    @functools.wraps(func)
    def wrapper_func(*wrapper_args, **wrapper_kwargs):
        if varargs is None:
            # remove extra positional arguments
            wrapper_args = wrapper_args[:len(args)]
        if kwvarargs is None:
            # remove extra keyword arguments
            wrapper_kwargs = {k: v for k, v in wrapper_kwargs.iteritems() if k in args}
        return func(*wrapper_args, **wrapper_kwargs)
    return wrapper_func

可以通过将if检查移出wrapper_func进行一些优化,但要花费编写更多代码的代价。