Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 292 – 简化字符串替换

作者:
Barry Warsaw <barry at python.org>
状态:
最终版
类型:
标准跟踪
创建日期:
2002年6月18日
Python 版本:
2.4
发布历史:
2002年6月18日,2004年3月23日,2004年8月22日
取代:
215

目录

摘要

本 PEP 描述了一个更简单的字符串替换功能,也称为字符串插值。本 PEP 在两个方面“更简单”:

  1. Python 当前的字符串替换功能(即 % 替换)复杂且容易出错。本 PEP 以牺牲部分表达性为代价,使其更简单。
  2. PEP 215 提出了另一种字符串插值功能,引入了一个新的 $ 字符串前缀。PEP 292 比这更简单,因为它不涉及语法更改,并且对字符串中可以发生的替换有更简单的规则。

基本原理

Python 目前支持一种基于 C 语言 printf() 的“%”格式化字符的字符串替换语法 [1]。尽管功能丰富,但 % 格式化代码也容易出错,即使对于经验丰富的 Python 程序员也是如此。一个常见的错误是遗漏了尾随的格式字符,例如 "%(name)s" 中的“s”。

此外,% 符号后面可以跟什么字符的规则相当复杂,而通常的应用很少需要这种复杂性。大多数脚本需要进行一些字符串插值,但其中大多数使用简单的“字符串化”格式,即 %s%(name)s。这种形式应该更简单且不易出错。

一个更简单的提议

我们建议添加一个名为 Template 的新类,它将存在于 string 模块中。Template 类支持新的字符串替换规则;它的值包含占位符,由 $ 字符引入。以下是 $ 占位符的规则:

  1. $$ 是一个转义符;它被替换为单个 $
  2. $identifier 命名一个替换占位符,匹配映射键“identifier”。默认情况下,“identifier”必须拼写为 [2] 中定义的 Python 标识符。$ 字符后的第一个非标识符字符终止此占位符规范。
  3. ${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

最后修改时间: 2025-02-01 08:55:40 GMT