【问题标题】:eval in template strings模板字符串中的 eval
【发布时间】:2012-05-28 22:50:02
【问题描述】:

我正在考虑将一个相当笨拙的 bash 脚本移植到 python,但我被困在如何处理以下方面:脚本的重点是根据动态获取的数据生成一个 png 图像。 bash 脚本抓取数据,并构建了一个很长的 convert 实用程序调用,其中有很多选项。看起来 python 的模板字符串将是一个很好的解决方案(我更愿意留在标准库中,因为我将部署到共享主机),但我发现你不能像在 bash 中那样评估表达式:

>>> from string import Template
>>> s = Template('The width times one is ${width}')
>>> s.substitute(width=45)
'The width times one is 45'
>>> t = Template('The width times two is ${width*2}')
>>> t.substitute(width=45)
# Raises ValueError

由于我的 bash 脚本在很大程度上依赖于这种算术(否则要跟踪的变量数量会成倍增加),我想知道是否有办法在 python 中模拟这种行为。看到this question,问的差不多,有评论,写着:

这将是非常不符合 Python 的,因为它违反直觉——字符串只是 字符串,它们不应该运行代码!

如果是这种情况,解决这个问题的更惯用方法是什么? 对上面链接的问题的建议答案是使用带有% 语法或format() 函数的字符串格式,但我认为这不适用于我的字符串中的变量数量(大约50)。

【问题讨论】:

    标签: string templates python


    【解决方案1】:

    为什么不使用内置的字符串格式?

    width = 45
    "Width times one is {width}".format(width=width)
    "Width times two is {width}".format(width=2*width)
    

    结果

    Width times one is 45
    Width times two is 90
    

    【讨论】:

    • 我认为公式应该是模板本身的一部分。
    • 老板想要一些模板来渲染,而不是几行硬编码的程序。
    • 我在最后一段中解决了这个问题。我有大约 50 个变量要插入到 80 行字符串中,我认为 .format() 成语不太合适。你不同意吗?
    • @Mayli 不,甚至不是那样,只是我认为不值得从 bash 翻译是不切实际的;你怎么看?
    • @NiklasB。是的,这将是我的偏好,因为我有 $((2 * $margin + $width)) 等实例,并且这些实例都需要在 .format() 方法中给出自己的名称
    【解决方案2】:

    这个问题的 Pythonic 解决方案是忘记字符串格式并将参数 列表 传递给 subprocess 函数之一,例如

    # I have no idea about convert's command line usage,
    # so here's an example using echo.
    subprocess.call(["echo", str(1 + 1), "bla"])
    

    这样,就无需构建单个字符串,也无需担心引用。

    【讨论】:

    • 我不认为引用是 OP 的问题。至少,它没有在任何地方提及
    • @NiklasB。引用不是问题,只是因为我还没有翻译成 python :) 我认为这比使用模板库更好地解决我的问题,因为它不需要外部代码并且避免显式构建一个巨大的字符串。
    • @mszep:很公平,我当时可能误解了这个问题;)
    【解决方案3】:

    您可能需要一个更好的模板引擎。 Jinja2 支持这种东西等等。我不认为标准库具有同等强大的功能,但据我所知,该库是纯 Python 的,因此您只需将其复制即可将其集成到您的应用程序中。

    如果 Jinja 由于某种原因不适合您,请查看 Python wiki,其中包含 a section specifically for those kinds of libraries。其中有一个非常轻量级的Templite,它只有一个类,似乎完全可以满足您的需求。

    【讨论】:

    • 感谢您的回答,但是,我认为使用外部模板库(无论多么轻量级)来满足我的需求有点矫枉过正,特别是因为我的字符串只构建一次并且不包含任何复杂的逻辑,只是值的替换。
    【解决方案4】:

    任务并不难,为什么不做一些有趣的编码呢?这里的功能几乎可以满足您的需求。

    import re
    def TempEval(template,**kwargs):
        mark = re.compile('\${(.*?)}')
        for key in kwargs:
            exec('%s=%s'%(key,kwargs[key]))
        for item in mark.findall(template):
            template=template.replace('${%s}'%item,str(eval(item)))
        return template
    
    
    print TempEval('The width times one is ${width}',width=5)
    #The width times one is 5
    print TempEval('The width times two is ${width*2}',width=5)
    #The width times two is 10
    

    【讨论】:

    • 这真的很酷,我没想到那样做...缺点是大型模板会变慢,因为您反复将“模板”分配给修改后的版本本身。但是,我认为我更喜欢@larsmans 的回答,因为它完全避免了显式构建字符串的需要。不过还是谢谢!
    • @mszep 您已将其标记为 pythonic。
    猜你喜欢
    • 2019-10-21
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2011-09-08
    相关资源
    最近更新 更多