Python:在包装函数中使用 *args、**kwargs
我正在为 Django 的 render_to_response() 编写一个包装函数来添加 CSRF 处理。
逻辑是:
def some_view (request)
dictionary = {'context_param': some_param}
dictionary.update(csrf(request))
# ... view code here
return render_to_response("a_template.html", dictionary)
render_to_response() 具有以下签名:
def render_to_response(*args, **kwargs)
我想编写透明包装器 - 只需添加一些功能(前面提到过)并保留其他内容不变。我想我应该写这样的东西:
def csrf_response (request, *args, **kwargs):
# Here I need to somehow extract dictionary from args or kwargs
if dictionary is None:
dictionary = {}
dictionary.update(csrf(request))
# And here I somehow need to pass dictionary into render_to_response() fot the furher processing
return render_to_response(*args, **kwargs)
所以问题是 - 从 args/kwargs 中提取所需参数(然后更改它)并进一步传递它的最佳实践是什么?
顺便说一句, render_to_response() 的代码让我觉得有点奇怪。这里是:
def render_to_response(*args, **kwargs):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
如果有人用所有位置参数调用它,那么 kwargs 将为空,但 mimetype
参数将被指定为最后一个位置参数怎么办?看起来在这种情况下它的行为是错误的。
I'm writing a wrapper function for Django's render_to_response() to add a CSRF processing.
The logic is:
def some_view (request)
dictionary = {'context_param': some_param}
dictionary.update(csrf(request))
# ... view code here
return render_to_response("a_template.html", dictionary)
render_to_response() has the following signature:
def render_to_response(*args, **kwargs)
I want to write transparent wrapper - just add some functionality (mentioned before) and leave other things as they are. I guess I should write someting like this:
def csrf_response (request, *args, **kwargs):
# Here I need to somehow extract dictionary from args or kwargs
if dictionary is None:
dictionary = {}
dictionary.update(csrf(request))
# And here I somehow need to pass dictionary into render_to_response() fot the furher processing
return render_to_response(*args, **kwargs)
So question is - what is the best practice for extracting needed parameter from args/kwargs, (then changing it) and passing it further?
BTW code of render_to_response() seemed me a bit strange. Here it is:
def render_to_response(*args, **kwargs):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
What if someone call it with all positional arguments, so kwargs will be empty, but mimetype
parameter will be specified as a last positional argument? Looks like in that case its behavior would be wrong.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
由于
render_to_response
的实现方式,指定 mimetype 的唯一方法是使用命名参数。作为位置参数传递的任何内容都将传递到 loader.render_to_string。如何提取某些论点并传递其他论点的方法实际上取决于您正在做什么。没有一种“正确”的方法可以始终做到这一点。当然,不同的作者有自己偏好的约定。
在您评论的地方
# Here I need to以某种方式从args或kwargs中提取字典
您可以直接使用kwargs作为字典,并将args作为元组,因为这正是它们的本质。对于参数,您别无选择,只能断言(即假设)每个位置的值的含义。我个人更喜欢,如果您编写的代码知道某些参数的值,则应在签名中声明它们,如下所示:
Because of how
render_to_response
is implemented, the only way to specify mimetype is by using a named argument. Anything passed as a positional argument will be passed on toloader.render_to_string
.The methodology for how to go about extracting certain arguments and passing on others really depends on what you're doing. There's no one "correct" way to always do it. Naturally, different authors have their own preferred conventions.
In the place of your comment
# Here I need to somehow extract dictionary from args or kwargs
you can use kwargs directly as a dictionary, and args as a tuple, because that's exactly what they are. For the args, you have no choice but to assert (i.e. assume) the meaning of the value in each position.I personally prefer that if you are writing code that knows the values of certain arguments, they should be declared in the signature, like so: