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

时间:2015-06-01 01:32:09

标签: python decorator

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

我有一些这样的功能:

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

2 个答案:

答案 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)