我试图找出如何编写装饰器以检查是否使用特定的可选参数调用该函数。这可能不是检查参数的pythonic方法,但我想知道使用装饰器的解决方案。以下是我正在寻找的一个例子:
@require_arguments("N", "p") # Question here
def g(x,*args,**kwargs):
if "N" not in kwargs: raise SyntaxError("missing N")
if "p" not in kwargs: raise SyntaxError("missing p")
print x
g(3,N=2) # Raise "missing p"
如何编写会引发相应错误的装饰器@require_arguments(*args)
?
答案 0 :(得分:4)
你走了:
def require_arguments(*reqargs):
def decorator(func):
def wrapper(*args, **kwargs):
for arg in reqargs:
if not arg in kwargs:
raise TypeError("Missing %s" % arg)
return func(*args, **kwargs)
return wrapper
return decorator
@require_arguments("N", "p") # Question here
def g(x,*args,**kwargs):
print x
g(3,N=2) # Raise "missing p"
输出:
Traceback (most recent call last):
File "arg.py", line 19, in <module>
g(3,N=2) # Raise "missing p"
File "arg.py", line 7, in wrapper
raise ValueError("Missing %s" % arg)
ValueError: Missing p
答案 1 :(得分:1)
dano的回答是正确的,我可以添加的唯一建议是:
使用functools.wraps
创建装饰器,这样就可以保留函数的名称及其 docstring 。
生成所有缺失参数的列表,而不是单个参数。我个人讨厌编译器说的时候:&#39; 你忘记了&#39;然后当我添加它时它仍然抱怨:&#39; 你忘记了b &#39;等等。
装饰者变成:
from functools import wraps
def require_arguments(*reqs):
def decorator(func):
@wraps(func)
def decorated(*args, **kwargs):
missing = [req for req in reqs if req not in kwargs]
if missing:
raise TypeError('missing ' + ', '.join(missing))
return func(*args, **kwargs)
return decorated
return decorator
@require_arguments('N', 'p')
def g(x, *args, **kargs):
"""just return x"""
print x
print g.__name__
print g.__doc__
try:
print g(3)
except TypeError as e:
print e
输出
g
just return x
missing N, p
如果您需要必要的参数,只需明确地询问它们:def g(x, N, p)
。您仍然可以调用g(x=2, N=5, p=3)
之类的函数来使代码更具表现力,即使您指定了参数,也可以使用不同的顺序。但是你将拥有一个固定的api(通常很好),你可以指定参数或使用固定的api顺序。
def f(a, b, c):
print a, b, c
f(1, 2, 3) # 1 2 3
f(c=1, b=2, a=3) # 3 2 1