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

Python 增强提案

PEP 3110 – 在 Python 3000 中捕获异常

作者:
Collin Winter <collinwinter at google.com>
状态:
最终版
类型:
标准跟踪
创建日期:
2006年1月16日
Python 版本:
3.0
发布历史:


目录

摘要

本PEP引入的更改旨在帮助消除Python语法中的歧义,简化异常类,简化异常的垃圾回收,并减小Python 3.0中语言的大小。

基本原理

  1. Python 2.x 中的 except 子句存在语法歧义,解析器无法区分
    except <expression>, <expression>:
    

    应该被解释为

    except <type>, <type>:
    

    except <type>, <name>:
    

    Python 2 选择后一种语义,代价是要求前者加括号,如下所示

    except (<type>, <type>):
    
  2. 正如 PEP 352 中所规定的,将移除将异常视为元组的能力,这意味着此代码将不再工作
    except os.error, (errno, errstr):
    

    因为自动解包将不再可能,所以希望移除使用元组作为 except 目标的能力。

  3. 正如 PEP 344 中所规定的,Python 3 中的异常实例将拥有一个 __traceback__ 属性。该 PEP 的“开放问题”部分包含一段关于此属性导致的垃圾回收困难的段落,即“异常 -> 回溯 -> 栈帧 -> 异常”的引用循环,所有局部变量都将保留在作用域内,直到下一次垃圾回收运行。本 PEP 旨在通过在 Python 3 的 except 子句中添加清理语义来解决此问题,即在 except 块结束时删除目标名称。
  4. 本着 “应该有一种——最好只有一种——显而易见的方法来做这件事” 的精神,合并重复的功能是可取的。为此,sys 模块的 exc_valueexc_typeexc_traceback 属性 [1] 将被删除,转而使用提供相同信息的 sys.exc_info()。这些属性已在 PEP 3100 中列为目标删除项。

语法变更

在 Python 3 中,except 语句的语法将从 [4] 变为

except_clause: 'except' [test [',' test]]

except_clause: 'except' [test ['as' NAME]]

使用 as 代替逗号标记意味着

except (AttributeError, os.error):

可以清楚地理解为异常类的元组。这种新语法最初由 Greg Ewing 提出 [2] 并得到 BDFL 的认可 ([2], [3])。

此外,as 后面的 token 从 test 限制为 NAME 意味着只有有效的标识符才能用作 except 目标。

请注意,上述语法总是要求将元组用括号括起来作为异常类。这样,模糊的

except A, B:

它在 Python 2.x 和 3.x 中将意味着不同的东西——导致难以捕获的错误——在 3.x 代码中是不能合法发生的。

语义变更

为了解决与 PEP 344 相关的垃圾回收问题,Python 3 中的 except 语句将生成额外的字节码来删除目标,从而消除引用循环。Phillip J. Eby 建议的源代码到源代码的转换 [5]

try:
    try_body
except E as N:
    except_body
...

被翻译成(用 Python 2.5 的术语来说)

try:
    try_body
except E, N:
    try:
        except_body
    finally:
        N = None
        del N
...

一个实现已经被检查到 py3k(以前是“p3yk”)分支 [6] 中。

兼容性问题

几乎所有 except 子句都需要更改。带有标识符目标的 except 子句将从

except E, N:

except E as N:

带有非元组、非标识符目标(例如,a.b.c[d])的 except 子句需要从

except E, T:

except E as t:
    T = t

这两种情况都可以通过 Guido van Rossum 的 2to3 工具 [7] 使用 except 修复器 [8] 来处理。

带有元组目标的 except 子句需要手动逐案转换。这些更改通常需要伴随异常类本身的更改。虽然这些更改通常无法自动化,但 2to3 工具能够指出 except 子句的目标是元组的情况,从而简化转换。

如果需要在 except 块结束之后保留异常实例,可以很容易地按如下方式转换:

try:
    ...
except E as N:
    ...
...

变成

try:
    ...
except E as N:
    n = N
    ...
...

这样,当 N 在块结束时被删除时,n 将继续存在并可正常使用。

最后,所有使用 sys 模块的 exc_typeexc_valueexc_traceback 属性的地方都将被删除。它们可以分别替换为 sys.exc_info()[0]sys.exc_info()[1]sys.exc_info()[2],这种转换可以通过 2to3sysexcattrs 修复器执行。

2.6 - 3.0 兼容性

为了方便 Python 2.6 和 3.0 之间的向前兼容,except ... as ...: 语法将反向移植到 2.x 系列。语法将因此从

except_clause: 'except' [test [',' test]]

except_clause: 'except' [test [('as' | ',') test]]

except 语句的“块结束清理”语义将不会包含在 2.x 系列版本中。

未解决的问题

替换或删除“sys.exc_info()”

关于放弃 sys.exc_info() 或将其替换为 sys.exception 属性或 sys.get_exception() 函数的想法已在 python-3000 上多次提出 ([9], [10]),并在 PEP 344 的“开放问题”部分提及。

虽然一个 2to3 修复器可以轻易地替换对 sys.exc_info() 的调用和一些属性访问,但对于静态分析来说,要找到并修复将 sys.exc_info() 的值作为参数的函数会困难得多。同样,这并没有解决需要重写所有以 sys.exc_info() 定义的 API 文档的需求。

实施

本 PEP 在修订版 53342 [11] 和 53349 [12] 中实现。对 2.6 中新 except 语法的支持在修订版 55446 [13] 中实现。

参考资料


来源:https://github.com/python/peps/blob/main/peps/pep-3110.rst

最后修改:2025-02-01 08:59:27 GMT