了解 pystache 中的 lambda

Understanding lambdas in pystache

假设我想在 pystache 中编写一个格式为 2 位浮点数的函数。

我想要上下文中的浮点数和函数(我相信这是 Mustache 的正确哲学)。

我该怎么办?

为了把问题说清楚,我将展示一对我写的代码片段。它们不起作用。

片段(一):

import pystache

tpl = "{{#fmt}}{{q}}{{/fmt}}"

ctx = {
    'q' : 1234.5678,
    'fmt' : lambda x: "%.2f" % float(x)
}

print pystache.render(tpl, ctx)

失败,错误 "could not convert string to float: {{q}}"。我能理解这个错误:{{fmt}} 在 {{q}} 之前求值。

代码段 (b):

import pystache

tpl = "{{#q}}{{fmt}}{{/q}}"

ctx = {
    'q' : 1234.5678,
    'fmt' : lambda x: "%.2f" % float(x)
}

print pystache.render(tpl, ctx)

失败并出现错误:"lambda() takes exactly 1 argument (0 given)"。我无法理解这个错误:上下文不应该作为参数传递吗?

简答:mustache 不支持这个。它期望所有数据值都经过预处理。

2012 年,在 formating of dates, numbers and more · Issue #41 · mustache/spec,人们提出了各种实施方案,包括。来自其他模板引擎,无法得出任何结论。

根据 mustache.js date formatting , ppl have constructed several extensions and/or workarounds (To me, the most promising one looks to be the {{value | format}} syntax extension),或建议转移到其他标记引擎。


附加信息:

规格 http://mustache.github.io/mustache.5.html (linked from http://mustache.github.io front page no less) is obsolete, dated 2009. The latest spec that pystache follows resides at https://github.com/mustache/spec , and looks abandoned, too: the latest commit is dated 02.2015 and the latest spec update is from 2011. Nor does it have a successor

因此,至此,标准已经失效,因此可以免费增加标记。

我仍然建议在重新发明轮子之前考虑上述讨论中链接的其他格式。

根据ivan_pozdeev的评论,我会post自己的回答。我不会接受它,因为我认为这是一个太丑陋的解决方案。

import pystache
import copy

tpl = "{{#fmt}}{{q}}{{/fmt}}"

ctx = {
    'q' : 1234.5678,
}

class OtherContext(object):
    def __init__(self, renderer):
        self.renderer = renderer

    def fmt(self):
        return lambda s: "%.2f" % float(copy.deepcopy(self.renderer).render(s, self.renderer.context))


renderer = pystache.Renderer(missing_tags='strict')

ctx2 = OtherContext(renderer)

print renderer.render(tpl, ctx, ctx2)

我也遇到了这个问题。在我用 lambda 调用的已定义方法上设置断点后,我发现 Pystache 传递的数据只是模板的 lambda 子部分。帮助不大。

然后,经过大量的挖掘,我发现 2013 年 11 月 5 日,来自 pystache.renderer 模块的 cjerdonek mentions accessing the current context via the renderer, and ultimately this code comment

# This is an experimental way of giving views access to the current context.
# [...]
@property
def context(self):
    """
    Return the current rendering context [experimental].
    """

    return self._context

谢天谢地,这个实验最终成功了:

  • 您的 lambda 必须调用已定义的方法。
    • 根据我的经验,严格的内联 lambda 不起作用。
  • 您定义的方法必须能够访问渲染器的实例 class。
    • 在该方法中,您将获取上下文、处理值并打印它。
  • 您的渲染器实例必须用于渲染您的模板和上下文,以便它可以访问上下文。

我构建了以下内容以满足您的要求。这是在 Python 3.6.5 中,为了便于阅读,我扩展了名称。

import pystache

RENDERER = None


def format_float(template):
    '''
    @param template: not actually used in your use case
        (returns '{{value}}' in this case, which you could render if needed)
    '''
    context_stack = RENDERER.context._stack
    # the data has been last in the stack in my experience
    context_data = context_stack[len(context_stack) - 1]
    x = float(context_data['value'])

    print("%.2f" % x)


if __name__ == '__main__':
    RENDERER = pystache.Renderer()

    template = '{{#formatter}}{{value}}{{/formatter}}'
    context = {
        'value' : 1234.5678,
        'formatter' : lambda template: format_float(template)
    }

    RENDERER.render(template, context)

这会将 1234.57 打印到控制台。