Python异常传播

16
我正在构建一个工具,当异常向上传播时,会向异常中添加有关异常上下文的新数据。 问题在于,当异常到达顶层时,所有额外的上下文数据都存在,但只显示最后一个堆栈跟踪。是否有一种简单的方法可以使异常显示抛出它的原始堆栈跟踪而不是最后一个堆栈跟踪,或者我应该做类似于第一次异常传播时获取原始堆栈跟踪的事情?
例如,以下代码:
def a():
    return UNBOUND
def b():
    try:
        a()
    except Exception as e:
        raise e
b()
产生了以下异常:
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    b()
  File "test.py", line 7, in b
    raise e
NameError: global name 'UNBOUND' is not defined

理想情况下,我希望以某种方式向用户展示这个信息:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
  File "test.py", line 2, in a
    return UNBOUND
NameError: global name 'UNBOUND' is not defined

这会将用户指向错误最初发生的那一行。


在Python 3.x中,我在堆栈跟踪中也看到了a()。Traceback (most recent call last): File "py3.py", line 13, in <module> b() File "py3.py", line 12, in b raise e File "py3.py", line 10, in b a() File "py3.py", line 7, in a return UNBOUND NameError: name 'UNBOUND' is not defined - daya
1个回答

38

Python的异常有点像Java,有一种方法可以使异常重新抛出而不截断堆栈。

只需使用没有参数的 raise。结果是:

Traceback (most recent call last):
  File "./exc.py", line 11, in <module>
    b()
  File "./exc.py", line 7, in b
    a()
  File "./exc.py", line 4, in a
    return UNBOUND
NameError: global name 'UNBOUND' is not defined

即使你在不带参数的情况下只是使用 raise,你仍然可以修改有关 e 对象的一些内容,例如:

e.args = ("hi!",)
raise 

实际上会改变异常消息。你也可以通过这种方式更改其他选项,而不破坏堆栈。


1
我已经写了很长时间的Python代码,但我不知道这个... 很好的答案。但是我在Python文档中找不到任何关于它的内容? - erb
2
@erb https://docs.python.org/3/reference/simple_stmts.html#grammar-token-raise-stmt请注意,这是一个Python文档链接,其中包含有关“raise”语句的语法和用法的详细信息。 - viraptor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接