PEP 758 – 允许 except
和 except*
表达式不带括号
- 作者:
- Pablo Galindo <pablogsal at python.org>, Brett Cannon <brett at python.org>
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 创建日期:
- 2024年9月30日
- Python 版本:
- 3.14
- 发布历史:
- 2024年10月2日
- 决议:
- 2025年3月14日
摘要
本PEP [1] 提议允许Python异常处理语法中的非括号式 except
和 except*
块,但仅限于不使用 as
子句的情况。目前,当捕获多个异常时,异常类型周围需要括号。这是Python 2的遗留问题。本PEP建议允许省略这些括号,从而简化语法,使其与语法中其他可选括号的部分更加一致,并在某些情况下提高可读性。
动机
当前捕获多个异常的语法要求 except
表达式(以及 except*
表达式)中使用括号。例如:
try:
...
except (ExceptionA, ExceptionB, ExceptionC):
...
虽然这种语法清晰明确,但在某些情况下可能会被视为不必要的冗长,尤其是在捕获大量异常时。通过允许省略括号,我们可以简化语法:
try:
...
except ExceptionA, ExceptionB, ExceptionC:
...
这一改变将使语法更符合Python中其他逗号分隔的列表,例如函数参数、函数调用内的生成器表达式和元组字面量,这些地方括号是可选的。
同样的改变也适用于 except*
表达式。例如:
try:
...
except* ExceptionA, ExceptionB, ExceptionC:
...
当使用 as
子句捕获异常实例时,必须像以前一样使用括号。一些用户表示,不要求括号会让他们感到困惑,因为不清楚究竟是什么被分配给了目标,因为在语言的其他部分,可以在类似情况下使用多个 as
子句(例如在导入和上下文管理器中)。这意味着如果一个 as
子句被添加到前面的例子中,它必须这样做:
try:
...
except (ExceptionA, ExceptionB, ExceptionC) as e:
...
基本原理
允许非括号式 except
块的决定基于以下考虑:
- 简洁性:取消括号要求简化了语法,使其与语言的其他部分更加一致。
- 可读性:在捕获许多异常的情况下,取消括号可以通过减少视觉混乱来提高可读性。
- 一致性:这一改变使得
except
子句与Python中其他明确的、逗号分隔的列表(不要求括号)更加一致。
规范
except
子句的语法将被修改,以允许非括号式的异常类型列表。语法将更新如下:
except_block:
| 'except' expressions ':' block
| 'except' expression 'as' NAME ':' block
| 'except' ':' block
except_star_block
| 'except' '*' expressions ':' block
| 'except' '*' expression 'as' NAME ':' block
这允许当前的括号式语法和新的非括号式语法,同时在使用 as
关键字时要求使用括号。
try:
...
except (ExceptionA, ExceptionB): # Still valid
...
except ExceptionC, ExceptionD: # New syntax
...
except (ExceptionE, ExceptionF) as e: # Parentheses still required
...
异常处理的语义保持不变。解释器将捕获列出的任何异常,无论它们是否带括号。
向后兼容性
此更改完全向后兼容。所有使用带括号的 except
和 except*
块的现有代码将继续无需修改即可工作。新语法纯粹是添加性的,不会破坏任何现有代码。
值得注意的是,在Python 2中,非括号式语法允许有两个元素,但具有不同的语义,其中列表的第一个元素用作异常类型,第二个元素用作捕获变量。此更改不会重新引入Python 2的语义,非括号式语法的行为将与括号版本完全相同。
安全隐患
此更改没有已知的安全隐患。异常处理的语义保持不变,这纯粹是语法上的更改。
如何教授此内容
对于新的Python用户,可以将非括号式语法作为捕获多个异常的标准方式进行教学。
try:
risky_operation()
except ValueError, TypeError, OSError:
handle_errors()
对于有经验的用户,它可以作为一种新的可选语法引入,可以与括号版本互换使用。文档应指出两种形式是等效的。
# These are equivalent:
except (ValueError, TypeError):
...
except ValueError, TypeError:
...
应该强调的是,这纯粹是语法上的更改,不影响异常处理的行为。
参考实现
概念验证实现可在 https://github.com/pablogsal/cpython/commits/notuples/ 获取。此实现修改了Python解析器以接受新语法,并确保其行为与括号版本完全相同。
被拒绝的想法
- 允许混合括号式和非括号式语法
try: ... except (ValueError, TypeError), OSError: ...
由于可能造成混淆并为了保持两种风格之间的清晰区分,此提议被拒绝。
延迟的想法
- 在使用
as
关键字时允许非括号式表达式。我们决定推迟这种特定形式的原因是,目前没有明确的共识,双方都有合理的论据,最安全的做法是保持括号要求,因为如果用户发现这种不一致过于严重,可以在以后取消,而如果取消后用户认为这是个坏主意,则不容易再恢复。
脚注
版权
本文档置于公共领域或 CC0-1.0-Universal 许可证下,以更宽松者为准。
来源:https://github.com/python/peps/blob/main/peps/pep-0758.rst