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. except 子句在 Python 2.x 中存在语法歧义,解析器无法区分
    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 的“未解决的问题”部分包含一段关于此属性引起的垃圾回收困难的段落,即“异常 -> 回溯 -> 栈帧 -> 异常”引用循环,其中所有局部变量都保留在范围内,直到下一次 GC 运行。本 PEP 旨在通过在 Python 3 中的 except 子句中添加清理语义来解决此问题,其中目标名称在 except 代码块的末尾被删除。
  4. 本着 “应该有一种——最好只有一种——显而易见的方法来做这件事” 的精神,需要整合重复的功能。为此,sys 模块的 [1] exc_valueexc_typeexc_traceback 属性将被删除,以支持 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 后面的标记从 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:

except 子句,其目标不是元组,也不是标识符(例如,a.b.c[d])需要从

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 ... as ...: 语法。2.x 系列的版本中将不包含 except 语句的代码块末尾清理语义。

未解决的问题

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

在 python-3000 上多次提出删除 sys.exc_info() 或将其替换为 sys.exception 属性或 sys.get_exception() 函数的想法([9][10]),并在 PEP 344 的“未解决的问题”部分中提到。

虽然用于替换对 sys.exc_info() 的调用和某些属性访问的 2to3 修复程序将微不足道,但对于静态分析来说,找到并修复将 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

上次修改:2023-09-09 17:39:29 GMT