Python:如何捕获异常链的内部异常?

Python: How to catch inner exception of exception chain?

考虑一个简单的例子:

1
2
3
4
5
6
7
def f():
    try:
        raise TypeError
    except TypeError:
        raise ValueError

f()

我想在f()执行后抛出ValueError时捕获TypeError对象。 有可能吗?

如果我执行函数f()那么python3打印到stderr异常链的所有异常异常(PEP-3134)就像

1
2
3
4
5
6
7
8
9
10
11
12
13
Traceback (most recent call last):
  File"...", line 6, in f
    raise TypeError
TypeError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File"...", line 11, in <module>
    f()
  File"...", line 8, in f
    raise ValueError
ValueError

所以我会得到异常链的所有异常列表或检查异常链中是否存在某种类型的异常(上例中的TypeError)。


Python 3在异常处理方面具有漂亮的语法增强功能。 而不是明显地提出ValueError,你应该从一个被捕获的异常中提出它,即:

1
2
3
4
try:
    raise TypeError('Something awful has happened')
except TypeError as e:
    raise ValueError('There was a bad value') from e

注意回溯之间的区别。 这个使用raise from版本:

1
2
3
4
5
6
7
8
9
10
11
Traceback (most recent call last):
  File"/home/user/tmp.py", line 2, in <module>
    raise TypeError('Something awful has happened')
TypeError: Something awful has happened

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File"/home/user/tmp.py", line 4, in <module>
    raise ValueError('There was a bad value') from e
ValueError: There was a bad value

虽然结果可能看起来相似,但实际上却有所不同! raise from保存原始异常的上下文,并允许跟踪所有异常链 - 这对于简单的raise是不可能的。

要获得原始异常,您只需要引用新异常的__context__属性,即

1
2
3
4
5
6
7
8
try:
    try:
        raise TypeError('Something awful has happened')
    except TypeError as e:
        raise ValueError('There was a bad value') from e
except ValueError as e:
    print(e.__context__)
>>> Something awful has happened

希望这是您正在寻找的解决方案。

有关更多详细信息,请参阅PEP 3134 - 异常链接和嵌入式回溯