访问decorator中的可选参数

时间:2014-02-25 03:53:15

标签: python decorator

我正在尝试访问传递给装饰器中的函数的所有参数,包括可选参数。考虑这个例子:

def decorator(fn):
    def wrapper(*args, **kwargs):
        print 'in wrapper', args, kwargs
        fn(*args, **kwargs)
    return wrapper

@decorator
def myFn(arg1, arg2, arg3=None):
    print 'in myFn', arg1, arg2, arg3

myFn(1,2)
myFn(1,2,3)

如果我这样做,我会得到:

in wrapper (1, 2) {}
in myFn 1 2 None
in wrapper (1, 2, 3) {}
in myFn 1 2 3

在第一次运行中,由于我没有指定3个参数,因此为了myFn,arg3被定义为None。但是arg3 == None在装饰器内部不可用,无论是在args还是kwargs中。如果我明确地将它传递给myFn,它将显示在装饰器内部,但如果我使用默认值,则无处可寻。

这是为什么?它怎么能修复?

2 个答案:

答案 0 :(得分:6)

这很正常,无法“修复”...

装饰器包装器拦截传递到函数的参数和关键字:换句话说,由函数调用者传递给函数本身的参数和关键字。

arg3=None是在函数范围定义的默认参数。在实际调用函数之前(直接或通过包装器)不能截获它,因为它在那时不存在。

但是,默认值存储在函数对象中:

def fn(arg1,arg2,arg3=None):
    pass

fn.func_defaults
-> (None,)

你可以使用下面的Get a function argument's default value?将默认值映射到参数...所以我想装饰器可能会花费极长的时间来打印传递和默认参数。所以我想我的第一个陈述并非100%正确:)

答案 1 :(得分:3)

您可以使用decorator包来保留功能签名:

from decorator import decorator

def decorate(f):
    def wrapper(f, *args, **kwargs):
        print 'in wrapper', args, kwargs
        return f(*args, **kwargs)
    return decorator(wrapper, f)

@decorate
def myFn(arg1, arg2, arg3=None):
    print 'in myFn', arg1, arg2, arg3

myFn(1, 2)
myFn(1, 2, 3)
myFn(1, 2, arg3=10)

<强>输出:

in wrapper (1, 2, None) {}
in myFn 1 2 None
in wrapper (1, 2, 3) {}
in myFn 1 2 3
in wrapper (1, 2, 10) {}
in myFn 1 2 10