PEP 536 – 字符串插值最终语法
- 作者:
- Philipp Angerer <phil.angerer at gmail.com>
- 状态:
- 已撤回
- 类型:
- 标准跟踪
- 创建日期:
- 2016-12-11
- Python 版本:
- 3.7
- 发布历史:
- 2016-08-18, 2016-12-23, 2019-03-15
- 决议:
- Discourse 消息
摘要
PEP 498 引入了字符串插值(或称“f-strings”)。但是,这些字面量中的表达式部分会受到某些限制。本 PEP 提出了一种正式的语法,取消了这些限制,将“f-strings”提升为“f-expressions”或 f-literals。
PEP 撤回
术语
本文将把现有语法称为“f-strings”,将提议的语法称为“f-literals”。
此外,本文将 f-literals/f-strings 中用 {} 分隔的表达式称为“表达式部分”,将它们周围的静态字符串内容称为“字符串部分”。
动机
CPython 中 f-strings 的当前实现依赖于现有的字符串解析机制及其令牌的后处理。这导致在 f-strings 中使用的表达式存在多种限制。
- 在表达式部分中,无法使用分隔 f-string 的引号字符。
>>> f'Magic wand: { bag['wand'] }' ^ SyntaxError: invalid syntax
- 先前考虑过的绕过此问题的方法会导致执行的代码中出现转义序列,而在 f-strings 中这是禁止的。
>>> f'Magic wand { bag[\'wand\'] } string' SyntaxError: f-string expression portion cannot include a backslash - 即使在多行 f-strings 中,也禁止使用注释。
>>> f'''A complex trick: { ... bag['bag'] # recursive bags! ... }''' SyntaxError: f-string expression part cannot include '#' - 表达式部分需要将
':'和'!'括在花括号内。>>> f'Useless use of lambdas: { lambda x: x*2 }' SyntaxError: unexpected EOF while parsing
从语言用户的角度来看,这些限制没有意义,可以通过为 f-literals 提供一个没有例外的常规语法并通过专门的解析代码来实现来解除这些限制。
基本原理
《动机》中提到的限制是不显而易见的,除非用户熟悉 f-literals 的实现细节,否则会感到反直觉。
如前所述,PEP 498 的一个早期版本允许在 f-strings 的任何地方使用转义序列,包括用来编码分隔表达式部分的括号以及在表达式代码中。它们将在代码被解析之前进行扩展,这将产生几个重要的影响:
#. 人类读者很难区分哪些部分是表达式,哪些是字符串。这为“混淆/卑鄙的 Python 挑战”提供了绝佳素材 #. 语法高亮器擅长解析嵌套语法,但对识别转义序列则不然。ECMAScript 2016 (JavaScript) 允许在其标识符中使用转义序列 [1],据作者所知,没有语法高亮器能够正确地突出显示利用这一点的代码。
因此,表达式部分将更难识别,无论是否有语法高亮器的帮助。通过新的语法,可以轻松扩展语法高亮器以正确解析和显示 f-literals。
f'Magic wand: {bag['wand']:^10}'
对可能包含转义序列的表达式部分进行高亮显示意味着需要为完整的表达式语法创建所有规则的修改副本,并考虑关键字、分隔符以及所有其他语言语法中出现转义序列的可能性。其中一个副本将产生一个级别的转义深度,并且必须为递归 f-literal 中更深的转义重复此过程。这是因为作者所知的没有高亮引擎支持在应用规则到特定上下文之前扩展转义序列。然而,嵌套上下文是所有高亮引擎的标准功能。
熟悉度也起着作用:在使用仅包含变量名的表达式而非纯变量名的字符串插值方法的每种其他语言中,都支持在没有转义序列扩展的情况下任意嵌套表达式。 [2]
规范
PEP 498 将 f-strings 指定为以下内容,但对其进行了限制:
f ' <text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ... '
正如下面解释的,PEP 中提到的所有限制都已从 f-literals 中解除。
- 表达式部分现在可以包含与分隔 f-literal 的引号类型相同的引号分隔的字符串。
- 反斜杠现在可以像在 Python 代码的其他任何地方一样出现在表达式中。在嵌套在 f-literals 中的字符串的情况下,当最内层的字符串被评估时,转义序列将被展开。
- 注释(使用
'#'字符)仅在多行 f-literals 中是可能的,因为注释以行尾结束(这使得单行 f-literal 无法正确闭合)。 - 表达式部分可以包含
':'或'!',只要语法上有效。第一个不在表达式中的':'或'!'之后必须是一个有效的强制类型转换或格式说明符。
一个未在 PEP 498 中明确提到的剩余限制是表达式部分的换行符。由于用单个 ' 或 " 字符分隔的字符串被预期为单行,因此在单行字符串的表达式部分中,换行符仍然是非法的。
注意
解除限制是否足够,还是应该指定一个更完整的语法?
向后兼容性
f-literals 完全向后兼容 f-strings,并扩展了被认为是合法的语法。
参考实现
待定
参考资料
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0536.rst
最后修改时间:2025-02-01 08:59:27 GMT