Python лямбда в мезонине утилит

Я не могу обернуть голову вокруг этой лямбда-функции (сделать). Это из утилиты Mezzanine:

def send_mail_template(subject, template, addr_from, addr_to, context=None,
                   attachments=None, fail_silently=None, addr_bcc=None,
                   headers=None):
    """
    Send email rendering text and html versions for the specified
    template name using the context dictionary passed in.

    EDITED FOR SIMPLICITY
    """

    context.update(context_settings())

    # Loads a template passing in vars as context.
    render = lambda type: loader.get_template("%s.%s" %
                      (template, type)).render(Context(context))

    # Create and send email.
    msg = EmailMultiAlternatives(subject, render("txt"),
                             addr_from, addr_to, addr_bcc,
                             headers=headers)
    msg.attach_alternative(render("html"), "text/html")
    msg.send(fail_silently=fail_silently)

Я пытаюсь передать список шаблонов в мою собственную версию функции. поэтому параметр "шаблон", представляющий собой строку пути к шаблону, становится списком (шаблонами) строк путей. Затем мне нужно перебрать список и применить все, что происходит в лямбде, а затем вызвать.render(Context(context)) для него.

это самый уродливый код, но он показывает, что мне нужно в качестве конечного результата:

render = lambda type: loader.get_template("%s.%s" %
                  (templates[0], type))

render2 = lambda type: loader.get_template("%s.%s" %
                  (templates[1], type))

# Create and send email.
msg = EmailMultiAlternatives(subject,(render("txt")+render2('txt')).render(Context(context)),
                         addr_from, addr_to, addr_bcc,
                         headers=headers)
msg.attach_alternative((render("html")+render2('html').render(Context(context)), "text/html")
msg.send(fail_silently=fail_silently)

Вышеописанное работает, но, очевидно, просто отвратительно, и список будет неизвестной длины.

Пожалуйста! Кто-нибудь может де-конструировать лямбда-функцию?

Answer with help from Arthur Tacca

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

def render_templates(types,templates,context):
    template_body = ''
    for template in templates:
        template_body += loader.get_template("%s.%s" % (template, types)).render(Context(context))
    return template_body

def send_mail_template(subject, templates, addr_from, addr_to, context=None,
                   attachments=None, fail_silently=None, addr_bcc=None,
                   headers=None):
    """
    ...
    """
    context.update(context_settings())

    msg = EmailMultiAlternatives(subject, render_templates("txt",templates,context),
                             addr_from, to, [],
                             headers)
    msg.attach_alternative(render_templates("html",templates,context), "text/html")

    msg.send(fail_silently=fail_silently)

1 ответ

Решение

Я не понимаю, почему вы используете функцию / лямбда вообще, а не просто (для первого примера):

rendered = loader.get_template("%s.%s" % (template, "txt")).render(Context(context))

Я предполагаю, что это упрощение работает только потому, что вы упростили контекст, в котором вы делаете это; возможно, в реальном коде вам нужно передать функцию рендеринга куда-нибудь, чтобы вызвать ее позже. Если нет, вы можете полностью избавиться от лямбд.

Вот небольшой момент, но он может немного прояснить ситуацию: нет абсолютно никакой разницы между

render = lambda type: loader.get_template("%s.%s" %
                  (templates[0], type))
render2 = lambda type: loader.get_template("%s.%s" %
                  (templates[1], type))

а также:

def render(type):
    return loader.get_template("%s.%s" % (templates[0], type))
def render2(type):
    return loader.get_template("%s.%s" % (templates[1], type))

(Хорошо, одно небольшое отличие состоит в том, что вы получаете более четкую трассировку стека, если есть исключение.) На самом деле вторая форма - лучший стиль (AKA "более Pythonic"); единственная причина использовать лямбду - если функция настолько коротка, что ее передают другой функции, даже не присваивая ее переменной.

В вашем случае это означает, что вы можете использовать итерацию, если вам нравится:

def render_all(types):
    result_list = []
    for type, template in zip(types, templates):
        result_list.append(loader.get_template("%s.%s" % (template, type)))
    return "".join(result_list)

Это созрели для понимания списка / генератора:

def render_all(types):
    return "".join(loader.get_template("%s.%s" % (template, type))
                   for type, template in zip(types, templates))
Другие вопросы по тегам