我有一个装饰器来验证一些参数并将验证的密钥传递给各种函数:
from functools import wraps
ref validate(f):
@wraps(f) # This is to ensure docstrings are passed through the decorated function
def redirect_if_invalid(request, *args, **kwargs):
if request.valid == False:
return HttpResponseRedirect('/login')
else:
newkwargs = { 'key': request.key }
return f(request, *args, **newkwargs)
return redirect_if_invalid
其他一些功能使用它:
@validate
def genericHandler(request, key)
pass
我会调用这样的函数:
genericHandler(request)
装饰者生成'key'kwarg。但是,我希望可以选择在其他方面传入密钥,即调用:
genericHandler(request, 'keydata')
目前这给了我一个错误:
TypeError: genericHandler() got multiple values for keyword argument 'key'
我该如何解决这个问题?重申一下,主要目标是能够使用或不使用可选参数调用genericHandler(),并让装饰器仅在缺少参数时生成参数。
到目前为止,在装饰器内部,我无法弄清楚如何确定是否传入了'key'参数,因为functools.wraps()似乎隐藏了它。
答案 0 :(得分:1)
如果您希望包装器的签名仍为(request, *args, **kwargs)
,则没有任何合理的方法可以执行此操作。另一方面,看起来你的装饰器已经假设包装函数采用key
参数,那么为什么不重写包装器来获取一个呢?在这种情况下,检查它是否已通过变得微不足道。
def validate(f):
@wraps(f)
def redirect_if_invalid(request, key=None):
# do the validation
if key is None:
key = request.key
return f(request, key)
return redirect_if_invalid
当然,如果您愿意,可以添加*args
和**kwargs
参数。
答案 1 :(得分:0)
所以对我来说,最好的方法就是明确地将kwargs作为kwargs传递。所以装饰的功能实际应该是:
@validate
def genericHandler(request, **kwargs)
key = kwargs.get('key')
pass
这样,我可以使用或不使用args调用该函数:
genericHandler(request)
或
genericHandler(request, **{ 'key' : key })
实际装饰看起来像:
def validate(f):
@wraps(f) # This is to ensure docstrings are passed through the decorated function
def redirect_if_invalid(request, *args, **kwargs):
key = kwargs.get('key')
if not key:
kwargs.set('key', request.key)
return f(request, *args, **kwargs)
return redirect_if_invalid