如何编写装饰器,使装饰后的函数可以接受(并忽略)任意参数?
我有一些这样的功能:
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)
捕获适当的函数,然后使用所有x
,y
,z
进行调用。为了避免因错误的参数数量而导致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
进行一些优化,但要花费编写更多代码的代价。