0

我有一个装饰器,它验证一些参数并将经过验证的密钥传递给各种函数:

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)

装饰器生成“关键”kwarg。但是,我想有选择地在其他时候传入密钥,即调用:

genericHandler(request, 'keydata')

目前这给了我一个错误:

TypeError: genericHandler() got multiple values for keyword argument 'key'

我怎样才能解决这个问题?重申一下,主要目标是能够在有或没有可选参数的情况下调用 genericHandler(),并且只有在缺少参数时才让装饰器生成参数。

到目前为止,在装饰器内部,我无法弄清楚如何确定是否传入了“key”参数,因为 functools.wraps() 似乎隐藏了它。

4

2 回答 2

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参数。

于 2013-09-10T00:30:15.050 回答
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
于 2013-09-10T04:41:31.963 回答