我想编写一个python函数装饰器来测试某个函数的某些参数是否通过了一些标准。例如,假设我想测试一些参数总是偶数,那么我希望能够做这样的事情(不是有效的python代码)
def ensure_even( n ) :
def decorator( function ) :
@functools.wraps( function )
def wrapper(*args, **kwargs):
assert(n % 2 == 0)
return function(*args, **kwargs)
return wrapper
return decorator
@ensure_even(arg2)
def foo(arg1, arg2, arg3) : pass
@ensure_even(arg3)
def bar(arg1, arg2, arg3) : pass
但我无法想象如何实现上述目标。有没有办法将特定参数传递给装饰器? (比如arg2表示foo,而arg3表示上面的bar)
谢谢!
答案 0 :(得分:11)
你可以这样做:
def ensure_even(argnum):
def fdec(func):
def f(*args, **kwargs):
assert(args[argnum] % 2 == 0) #or assert(not args[argnum] % 2)
return func(*args, **kwargs)
return f
return fdec
那么:
@ensure_even(1) #2nd argument must be even
def test(arg1, arg2):
print(arg2)
test(1,2) #succeeds
test(1,3) #fails
答案 1 :(得分:4)
我之前的回答错过了你的问题。
这是一个更长的解决方案:
def ensure_even(*argvars):
def fdec(func):
def f(*args,**kwargs):
for argvar in argvars:
try:
assert(not args[func.func_code.co_varnames.index(argvar)] % 2)
except IndexError:
assert(not kwargs[argvar] % 2)
return func(*args,**kwargs)
return f
return fdec
所以这是用法:
@ensure_even('a','b')
def both_even(a,b):
print a,b
@ensure_even('even')
def first_even(even, arg2):
print even, arg2
both_even(2,2)
first_even(2,3)
both_even(2,1) #fails
虽然我不确定它是否适用于所有情况。