重新抛出Python异常。该捕获哪个?

52 投票
3 回答
80600 浏览
提问于 2025-04-18 15:05

我正在学习使用Python,最近看到了一篇文章:http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html。这篇文章讲的是在Python中如何重新抛出异常,像这样:

try:
    do_something_dangerous()
except:
    do_something_to_apologize()
    raise

因为你重新抛出了异常,所以应该有一个“外层的捕获-异常”语句。但是我在想,如果在这个捕获的部分,do_something_to_apologize() 里面又抛出了一个错误,那外层的“捕获-异常”会捕获到哪个呢?是你重新抛出的那个,还是do_something_to_apologize() 抛出的那个?或者说,优先级高的异常会先被捕获吗?

3 个回答

4

我觉得更好的办法是使用

raise NewException("Explain why") from CatchedException

这种模式。特别是,考虑到Python 3,以及@BrenBarn给出的例子,我使用了以下代码

def failure():
    raise ValueError("Real error")

try:
    failure()
except ValueError as ex:
    raise TypeError("Apology error") from ex

这样可以得到

--------- ValueError----                                
Traceback (most recent call last) 
      4 try:
----> 5     failure()
      6 except ValueError as ex:

      1 def failure():
----> 2     raise ValueError("Real error")
      3 

ValueError: Real error

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

-----TypeError-----
Traceback (most recent call last) 
      5     failure()
      6 except ValueError as ex:
----> 7     raise TypeError("Apology error") from ex

TypeError: Apology error
8

do_something_to_apologize()这个函数抛出的错误会被捕获。包含raise的那一行代码是不会执行的,因为do_something_to_apologize抛出了一个错误。而且,我认为在Python的错误处理中并没有“优先级”这个概念。

89

试试看,看看结果:

def failure():
    raise ValueError, "Real error"

def apologize():
    raise TypeError, "Apology error"

try:
    failure()
except ValueError:
    apologize()
    raise

结果是:

Traceback (most recent call last):
  File "<pyshell#14>", line 10, in <module>
    apologize()
  File "<pyshell#14>", line 5, in apologize
    raise TypeError, "Apology error"
TypeError: Apology error

原因是:原来的函数里的“真正的”错误已经被except捕获了。apologize在到达raise之前就抛出了一个新的错误。因此,except里的raise根本没有被执行,只有apologize抛出的错误向上传播。如果apologize抛出一个错误,Python就无法知道你在apologize之后还打算抛出一个不同的异常。

需要注意的是,在Python 3中,错误追踪信息会提到两个异常,并且会有说明第二个异常是怎么产生的消息:

Traceback (most recent call last):
  File "./prog.py", line 9, in <module>
  File "./prog.py", line 2, in failure
ValueError: Real error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./prog.py", line 11, in <module>
  File "./prog.py", line 5, in apologize
TypeError: Apology error

不过,第二个异常(“道歉”异常)仍然是唯一一个向外传播的,并且可以被更高层的except捕获。原来的异常在追踪信息中提到,但被后来的异常包含了,无法再被捕获。

撰写回答