PEP 292 – 更简单的字符串替换
- 作者:
- Barry Warsaw <barry at python.org>
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 创建:
- 2002-06-18
- Python 版本:
- 2.4
- 历史记录:
- 2002-06-18, 2004-03-23, 2004-08-22
- 替换:
- 215
摘要
本 PEP 描述了一种更简单的字符串替换功能,也称为字符串插值。本 PEP 在两个方面“更简单”
基本原理
Python 目前支持基于 C 的printf()
的‘%
’格式化字符[1]的字符串替换语法。虽然功能非常丰富,但%
格式化代码也容易出错,即使对于经验丰富的 Python 程序员也是如此。一个常见的错误是省略尾部的格式化字符,例如"%(name)s"
中的‘s
’。
此外,%
符号后面可以跟什么字符的规则相当复杂,而通常的应用很少需要这种复杂性。大多数脚本都需要进行一些字符串插值,但其中大部分使用简单的“字符串化”格式,即%s
或%(name)s
。此形式应该更简单且更不容易出错。
一个更简单的提案
我们建议添加一个名为Template
的新类,它将位于 string 模块中。Template
类支持新的字符串替换规则;其值包含占位符,由$
字符引入。以下规则适用于$
占位符
$$
是转义符;它将被替换为单个$
$identifier
命名一个替换占位符,该占位符与“identifier”的映射键匹配。默认情况下,“identifier”必须拼写一个 Python 标识符,如[2]中定义。$
字符后面的第一个非标识符字符终止此占位符规范。${identifier}
等效于$identifier
。当有效的标识符字符位于占位符之后但不是占位符的一部分时,需要使用它,例如"${noun}ification"
。
如果$
字符出现在行尾,或后跟任何其他字符(而不是上面描述的字符),则在插值时会引发ValueError
。映射中的值会自动转换为字符串。
没有其他字符具有特殊含义,但是可以从Template
类派生以定义不同的替换规则。例如,派生类可以允许占位符中使用句点(例如,支持某种动态命名空间和属性路径查找),或者可以定义除$
以外的分隔符字符。
创建Template
后,可以通过调用以下两种方法之一执行替换
substitute()
。此方法返回一个新字符串,该字符串是在Template
中的占位符被映射的值替换后的结果。如果存在映射中不存在的占位符,则会引发KeyError
。safe_substitute()
。这类似于substitute()
方法,除了永远不会引发KeyErrors
(由于映射中缺少占位符)。当占位符缺失时,原始占位符将出现在结果字符串中。以下是一些示例
>>> from string import Template >>> s = Template('${name} was born in ${country}') >>> print s.substitute(name='Guido', country='the Netherlands') Guido was born in the Netherlands >>> print s.substitute(name='Guido') Traceback (most recent call last): [...] KeyError: 'country' >>> print s.safe_substitute(name='Guido') Guido was born in ${country}
substitute()
和safe_substitute()
的签名允许将占位符到值的映射作为第一个位置参数中的单个类似字典的对象传递,或者如上所示作为关键字参数传递。这两种方法的确切细节和签名保留在标准库文档中。
为什么使用$
和花括号?
BDFL 最好地说明了这一点[3]:“$
在除了 Perl 之外的许多语言中都表示“替换”,我想知道你去哪里了。[…] 我们是从 shell 中复制的。”
因此,选择替换规则是因为它与许多其他语言相似。这使得替换规则更容易教授、学习和记忆。
与 PEP 215 的比较
PEP 215 描述了字符串插值的替代方案。与该 PEP 不同,此 PEP 没有为 Python 提出任何新的语法。所有建议的新功能都体现在一个新的库模块中。PEP 215 提出了一种新的字符串前缀表示法,例如$""
,它向 Python 信号存在一种新的字符串类型。$
字符串必须与现有的 r 前缀和 u 前缀交互,基本上使字符串前缀组合的数量增加了一倍。
PEP 215 还允许在$
字符串内使用任意 Python 表达式,以便您可以执行以下操作
import sys
print $"sys = $sys, sys = $sys.modules['sys']"
这将返回
sys = <module 'sys' (built-in)>, sys = <module 'sys' (built-in)>
人们普遍认为PEP 215中的规则是安全的,因为它们没有引入新的安全问题(有关详细信息,请参阅PEP 215,“安全问题”)。但是,这些规则仍然相当复杂,并且使得在原始$
字符串中更难以看到替换占位符。
有趣的是,本 PEP 中定义的Template
类旨在用于继承,并且只需稍微多做一些工作,就可以使用现有的 Python 语法支持PEP 215的功能。
例如,可以定义Template
和 dict 的子类,允许更复杂的占位符语法和评估这些占位符的映射。
国际化
该实现通过在Template
实例的template
属性中记录原始模板字符串来支持国际化。此属性将用作基于 gettext 的目录中的查找键。应用程序需要负责将结果字符串转换回Template
以进行替换。
但是,Template
类旨在通过支持混合Template
和 unicode 子类在国际化应用程序中更直观地工作。因此,国际化应用程序可以创建一个特定于应用程序的子类,从Template
和 unicode 多重继承,并使用该子类的实例作为 gettext 目录键。此外,子类可以将特殊的__mod__()
方法别名为.substitute()
或.safe_substitute()
,以提供更传统的字符串/unicode 类似%
运算符替换语法。
参考实现
该实现[4]已提交到 Python 2.4 源代码树中。
参考文献
版权
本文档已进入公有领域。
来源: https://github.com/python/peps/blob/main/peps/pep-0292.rst
上次修改: 2023-09-09 17:39:29 GMT