Python 异常传播

16 投票
1 回答
24261 浏览
提问于 2025-04-15 16:56

我正在制作一个工具,当出现异常时,它会向上层传递,同时在异常中添加关于异常上下文的新数据。问题是,当异常到达最上层时,所有额外的上下文数据都在里面,但只显示了最新的调用栈信息。有没有简单的方法可以让异常显示它最初抛出时的调用栈,而不是最后的调用栈?还是说我应该在异常第一次传递时就抓取原始的调用栈?

比如,下面这段代码:

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

这样可以指向错误最初发生的那一行。

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 

这实际上会改变异常的提示信息。你可能还可以通过这种方式改变其他选项,而不会破坏调用栈的信息。

撰写回答