PEP 845:前导点值模式

PEP 845:前导点值模式

💡 原文英文,约1700词,阅读约需6分钟。
📝

内容提要

PEP 845 提议在 match 语句中允许以点号前缀的简单名称(如 `.author`)作为值模式,按正常名称解析规则查找并比较,而非捕获。这解决了匹配局部变量、全局变量和哨兵值时需用 guard 子句的麻烦,语法向后兼容,社区投票中 71% 支持点号方案。

🔎

延伸解读

点号前缀的解析规则

PEP 845 规定,以点号前缀的简单名称(如 .author)在 match 语句中按正常名称解析规则查找,即依次在局部、闭包、全局和内置作用域中搜索,然后与匹配主体进行相等比较。点号仅表示该模式执行查找而非绑定,并不限定作用域。这与相对导入中的点号含义不同,后者表示相对于当前包。

与现有写法的对比

此前要匹配局部变量或全局变量,需使用捕获模式加 guard 子句,例如 case {"author": book_author} if book_author == author。这种写法在复杂模式中可读性差,且无法直接匹配哨兵值。点号方案允许直接写 case {"author": .author},语法更简洁,且完全向后兼容,因为 .name 此前会引发 SyntaxError。

社区投票与替代方案

在伴随讨论的投票中,71% 的受访者支持前导点号语法,高于其他替代方案。其他被考虑过的标记包括 ^CONSTANT、$CONSTANT、?CONSTANT、==CONSTANT、{CONSTANT} 和反引号,但它们的支持率均低于点号。点号已是现有值模式的一部分,且不会与映射模式或比较运算符混淆。

对内置常量和类型匹配的影响

由于点号模式按正常名称解析,内置作用域中的名称也可被匹配。例如 NotImplemented 和 Ellipsis 是普通名称而非关键字,裸用时会成为捕获模式,但写成 .NotImplemented 或 .Ellipsis 即可作为值模式。类似地,case .int: 匹配类型对象本身,而 case int(): 匹配 int 的实例,两者语义不同。

❓

Q&A

PEP 845 提议在 match 语句中增加什么新语法?

PEP 845 提议允许在 match 语句的值模式中使用以点号前缀的简单名称(如 `.author`),该名称会按照正常的名称解析规则查找并与匹配主题进行相等比较,而不是作为捕获模式。

为什么需要前导点值模式?它解决了什么问题?

在 PEP 634 中,值模式只支持带点的属性(如 `Color.RED`),无法直接匹配局部变量、全局变量或哨兵值,必须使用 guard 子句等变通方法,导致代码难以阅读和编写。前导点值模式允许直接匹配这些值,无需 guard 子句。

前导点值模式的语法规则是什么?

值模式扩展为支持以点号前缀的简单名称,语法为 `.NAME`,其中点号后必须恰好跟一个标识符,不允许属性链(如 `.ns.CONST` 无效)。映射模式的键也可以使用前导点名称。查找遵循标准 Python 名称解析规则。

前导点值模式与现有的值模式规则如何统一?

现有规则是“值模式中包含点表示查找;不带点的名称模式表示绑定”。前导点形式将这一规则扩展到非限定名称,即“名称模式中任何位置出现点都表示查找”。

社区对前导点语法的支持度如何?

在伴随讨论的投票中,71% 的受访者支持前导点语法,超过其他替代方案和现状。

前导点值模式是否向后兼容?

是的,该变更完全向后兼容。此前使用 `.name` 会引发 SyntaxError,因此不会影响现有代码。

前导点值模式有哪些替代方案被考虑过?

替代方案包括 `^CONSTANT`、`$CONSTANT`、`?CONSTANT`、`==CONSTANT`、`{CONSTANT}`、反引号,以及 `case value MISSING:`、`case constant MISSING:` 等关键字形式,还有使用 `global.NAME`、`nonlocal.NAME` 等伪命名空间。这些方案在投票中获得的批准均少于前导点形式。

前导点值模式如何处理名称解析作用域?

点号不选择作用域,名称按照普通表达式中的解析规则进行解析(局部、闭包、全局、内置作用域)。点号仅决定模式是执行查找还是绑定。

前导点值模式可以用于匹配内置常量如 NotImplemented 吗?

可以。由于名称解析包括内置作用域,前导点形式允许匹配那些通常只能作为裸名称使用的值,例如 `NotImplemented`、`Ellipsis` 以及内置类型对象(如 `.int` 匹配类型对象本身,而非实例)。

🏷️

标签

➡️

继续阅读