Python: использование *args, **kwargs в функциях-оболочках

#django #wrapper #keyword-argument #args #render-to-response

#django #оболочка #ключевое слово-аргумент #аргументы #рендеринг в ответ

Вопрос:

Я пишу функцию-оболочку для render_to_response() Django, чтобы добавить обработку 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 параметр будет указан в качестве последнего позиционного аргумента? Похоже, что в этом случае его поведение было бы неправильным.

Ответ №1:

Из-за того, как render_to_response реализован, единственный способ указать mimetype — это использовать именованный аргумент. Все, что передается в качестве позиционного аргумента, будет передано в loader.render_to_string .

Методология извлечения определенных аргументов и передачи других действительно зависит от того, что вы делаете. Нет ни одного «правильного» способа всегда это делать. Естественно, у разных авторов есть свои собственные предпочтительные соглашения.

Вместо вашего комментария # Here I need to somehow extract dictionary from args or kwargs вы можете использовать kwargs непосредственно как словарь, а args как кортеж, потому что это именно то, чем они являются. Для аргументов у вас нет выбора, кроме как утверждать (т. Е. предполагать) значение значения в каждой позиции.

Лично я предпочитаю, чтобы, если вы пишете код, который знает значения определенных аргументов, они должны быть объявлены в подписи, вот так:

 def spam(session, name, *args, clear=True, **kwargs):
  # do something with session, name, clear
  return eggs(name, *args, **kwargs)  # if eggs requires name
  

Комментарии:

1. «вы можете использовать kwargs непосредственно как словарь» — dictionary не является Python dict — это необязательный параметр render_to_response() функции, который описан в документации следующим образом: render_to_response(template[, dictionary][, context_instance][, mimetype])

2. О, я думаю, теперь я понимаю. Я написал свою собственную функцию «filterkeys», которая возвращает новый dict, содержащий только ключи, которые я хочу сохранить, на основе логической функции. Используя что-то подобное, вы можете фильтровать kwargs, а затем передавать его во внутреннюю функцию.