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

Python 增强提案

PEP 409 – 抑制异常上下文

作者:
Ethan Furman <ethan at stoneleaf.us>
状态:
最终版
类型:
标准跟踪
创建日期:
2012 年 1 月 26 日
Python 版本:
3.3
发布历史:
2002 年 8 月 30 日,2012 年 2 月 1 日,2012 年 2 月 3 日
取代者:
415
决议:
Python-Dev 消息

目录

摘要

PEP 3134 的一个开放问题是抑制上下文:目前没有办法做到这一点。本 PEP 提出了一个方案。

基本原理

生成异常有两种基本方式

  1. Python 自身(有 bug 的代码、缺少资源、结束循环等)
  2. 手动(使用 raise 语句)

在编写库,甚至只是自定义类时,可能需要抛出异常;此外,将一个异常更改为另一个异常可能很有用,甚至有必要。以我的 dbf 模块为例

try:
    value = int(value)
except Exception:
    raise DbfError(...)

无论原始异常是什么(ValueErrorTypeError 或其他),都无关紧要。从这一点开始的异常是 DbfError,并且原始异常没有价值。但是,如果打印此异常,我们目前会看到两者。

备选方案

已经提出了几种可能性

  • raise as NewException()

    重新使用 as 关键字;可能令人困惑,因为我们并未真正重新抛出原始异常

  • raise NewException() from None

    遵循现有语法,明确声明原始异常

  • exc = NewException(); exc.__context__ = None; raise exc

    上一方法的非常冗长的方式

  • raise NewException.no_context(...)

    将上下文抑制设为类方法。

所有上述选项都需要对核心进行更改。

提案

我建议采用第二个选项

raise NewException from None

它的优点是使用现有的模式明确设置原因

raise KeyError() from NameError()

但由于原因是 None,因此默认异常打印例程不会显示以前的上下文。

实现讨论

注意:在此 PEP 获得批准后,在 PEP 415 中提出并接受了一个更简洁的实现机制。有关 Python 3.3 中实际使用的实现的更多详细信息,请参阅该 PEP。

目前,None__context____cause__ 的默认值。为了支持 raise ... from None(它会将 __cause__ 设置为 None),我们需要一个不同的 __cause__ 默认值。提出了几种关于如何在语言级别实现此目的的想法

  • 覆盖以前的异常信息(绕过问题并将 __cause__ 保持为 None)。

    由于错误消息不佳,这会严重阻碍调试,因此被拒绝。

  • __cause__ 中使用其中一个布尔值:False 将是默认值,当 from ... 与显式链接的异常或 None 一起使用时,它将被替换。

    被拒绝,因为这鼓励为 __cause__ 使用两种不同的对象类型,其中一种(布尔值)不允许具有所有可能的完整值范围(True 永远不会被使用)。

  • 创建一个特殊的异常类 __NoException__

    被拒绝,因为它可能令人困惑,可能被用户错误地引发,并且不是像 NoneTrueFalse 那样真正独特的值。

  • 使用 Ellipsis 作为默认值(... 单例)。

    已接受。

    省略号在英语中常被用作省略单词时的占位符。这在这里对我们有利,作为 __cause__ 被省略的信号,因此请在 __context__ 中查找更多详细信息。

    Ellipsis 不是异常,因此不能被引发。

    只有一个 Ellipsis,因此没有未使用的值。

    错误信息不会被丢弃,因此即使默认代码不跟踪,自定义代码也可以跟踪整个异常链。

语言细节

为了支持 raise Exception from None__context__ 将保持不变,但 __cause__ 将以 Ellipsis 开始,并在使用 raise Exception from None 方法时更改为 None

形式 __context__ __cause__
raise 省略号
reraise 上一个异常 省略号
reraise from None | ChainedException 上一个异常 None | 显式链接的异常

默认的异常打印例程将

  • 如果 __cause__Ellipsis,则会打印 __context__(如果有的话)。
  • 如果 __cause__None,则不会打印 __context__
  • 如果 __cause__ 是其他任何东西,则会打印 __cause__

在后两种情况下,异常链将停止被跟踪。

因为 __cause__ 的默认值现在是 Ellipsis,并且 raise Exception from Cause 只是语法糖

_exc = NewException()
_exc.__cause__ = Cause()
raise _exc

现在,EllipsisNone 都允许作为原因

raise Exception from Ellipsis

补丁

有一个 CPython 补丁实现了这一点,附加到 Issue 6210

参考资料

python-dev 上的此线程中进行了讨论和改进。


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

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