如何修改functools.wraps存储的参数?

时间:2013-09-10 00:05:44

标签: python functools

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

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()似乎隐藏了它。

2 个答案:

答案 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