【问题标题】:advanced string formatting vs template strings高级字符串格式化与模板字符串
【发布时间】:2012-07-22 17:25:48
【问题描述】:

我想知道使用template strings 代替新的advanced string formatting 是否有优势?

【问题讨论】:

  • 这是一个很难用模板字符串做的stackoverflow.com/questions/11388180
  • 好问题 (+1)。有趣的是,在此之前我从未认真阅读过文档中关于模板字符串的部分......

标签: python string-formatting template-engine


【解决方案1】:

模板旨在比通常的字符串格式更简单,但以牺牲表现力为代价。 PEP 292 的基本原理是将模板与 Python 的 % 样式的字符串格式进行比较:

Python 目前支持基于以下的字符串替换语法 C 的 printf() '%' 格式化字符。虽然相当有钱, % 格式的代码也容易出错,即使对于 经验丰富的 Python 程序员。一个常见的错误是离开 尾随格式字符,例如s%(name)s.

此外,% 符号后面的规则是公平的 复杂,而通常的应用程序很少需要这种复杂性。 大多数脚本需要做一些字符串插值,但大多数 那些使用简单的“字符串化”格式,即%s%(name)s 这种形式应该更简单,更不容易出错。

虽然新的.format() 改善了这种情况,但format string syntax 确实相当复杂,因此其基本原理仍然有其道理。

【讨论】:

  • 那么字符串模板的唯一优势就是不那么复杂?
  • @P3trus:基本上,是的。有时不同的元字符也可能适合不同的情况。例如,如果您将 C 代码的 sn-p 写入文件并替换了一些字符串,则模板字符串可能更可取,因为您不需要将所有大括号都加倍来转义它们,并且因为 $ 没有任何C中的特殊含义。
  • 模板字符串可以更安全realpython.com/python-string-formatting/…
【解决方案2】:

这主要是语法偏好问题,通常归结为懒惰/冗长的权衡以及对现有字符串模板系统的熟悉/习惯。在这种情况下,模板字符串更懒惰/简单/快速编写,而.format() 更冗长且功能齐全。

习惯于 PHP 语言或 Jinja 系列模板系统的程序员可能更喜欢模板字符串。使用“%s”位置样式的元组替换可能会吸引那些使用类似printf 的字符串格式或想要快速的东西的人。 .format() 有更多功能,但除非您需要只有 .format() 提供的特定功能,否则使用任何现有方案都没有问题。

唯一需要注意的是,命名字符串模板比依赖顺序的模板更灵活,需要更少的维护。除此之外,这一切都取决于个人喜好或您正在从事的项目的编码标准;

【讨论】:

  • @P3trus 你误会我了。我的意思是,尽管这两种方法都提供了有序的 命名字段作为一项功能,但命名字段更灵活、更健壮,无论您使用什么模板 API;这是对两种方法共同特征的价值判断,而不是对方法本身的价值判断。
  • 我看不出模板何时会比 format() 更简洁,例如string.Template('bob is $age years old').substitute(age=age)'bob is {age} years old'.format(age)
【解决方案3】:

字符串模板的一个关键优势是您只能使用safe_substitutemethod 替换一些 占位符。如果未向占位符传递值,普通格式字符串将引发错误。例如:

"Hello, {first} {last}".format(first='Joe')

加注:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'last'

但是:

from string import Template
Template("Hello, $first $last").safe_substitute(first='Joe')

生产:

'Hello, Joe $last'

注意返回值是字符串,不是Template;如果要替换 $last,则需要从该字符串创建一个新的 Template 对象。

【讨论】:

  • 你确定这是优势吗?
  • Template("Hello, $first $last").safe_substitute(first='Joe') 什么也没产生。你必须打印它。 :)
  • 不能将此视为优势。处理异常肯定更好吗?
  • 这在想要执行两层模板的情况下可能是一个优势,即想要从另一个模板字符串生成模板字符串,并将剩余的替换推迟到第二个模板.我刚刚在代码审查中遇到了这样一种情况,有人有理由逐步执行模板替换。
  • 非常有用用于模板化正则表达式模式,其中使用了{variant_text}_\d{4} 类型的语法,因为典型的str.format() 函数需要“4”的值。这解决了这个问题。如果可以的话,我会投 10 票。
【解决方案4】:

不管怎样,从 dict 进行模板替换似乎比格式替换慢 4 到 10 倍,具体取决于模板的长度。这是我在 OS X 上运行的 2.3 GHz 内核 i7 和 Python 3.5 的快速比较。

from string import Template
lorem = "Lorem ipsum dolor sit amet {GIBBERISH}, consectetur adipiscing elit {DRIVEL}. Expectoque quid ad id, quod quaerebam, respondeas."
loremtpl = Template("Lorem ipsum dolor sit amet $GIBBERISH, consectetur adipiscing elit $DRIVEL. Expectoque quid ad id, quod quaerebam, respondeas.")
d = dict(GIBBERISH='FOOBAR', DRIVEL = 'RAXOOP')

In [29]: timeit lorem.format(**d)
1.07 µs ± 2.13 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [30]: timeit loremtpl.substitute(d)
8.74 µs ± 12.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

我测试的最坏情况是 13 个字符的字符串慢了大约 10 倍。我测试的最好情况是 71000 个字符的字符串慢了大约 4 倍。

【讨论】:

  • 我认为这只是错字,但 In[29] 有 1000000 个循环,而 In[30] 有 100000 个循环。请确认。
  • @sandeep 这不是错字。 ipython timeit 命令很聪明。它只运行所需数量的循环以获得准确的估计。模板版本大约慢了一个数量级,并且时间它需要相应地更少的循环来达到结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
相关资源
最近更新 更多