如何编写装饰器以使装饰函数可以接受(并忽略)任意参数?
我有一些这样的功能:
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
答案 0 :(得分:4)
您可以使用inspect.getargspec
来确定修饰函数采用的参数:
.bak
可以通过提取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
来优化这一点,但代价是编写更多代码。
答案 1 :(得分:1)
您可以使用named arguments并始终调用foo()
(第一个函数)以便调度到“right”函数,如下所示:
def foo(a, b=None, c=None, d=None):
if b:
return foo2(a, b, c, d)
else:
# do your thing
def foo2(a, b, c=None, d=None):
if c:
return foo3(a, b, c, d)
else:
# do your thing
def foo3(a, b, c, d=None):
...
另一种选择:
def foo(a, *b):
if b:
return foo2(a, *b)
else:
print "in foo"
# do your thing
def foo2(a, b, *c):
if c:
return foo3(a, b, *c)
else:
print "in foo2"
# do your thing
def foo3(a, b, c, *d):
print "in foo3"
foo(1, 2, 3)