python:即使在try/except子句中捕获,也会引发异常

Python: Exception raised even when caught in try/except clause

本问题已经有最佳答案,请猛点这里访问。

在我的代码中,我想在异常发生时捕获它,将异常旁边的一些信息打印到屏幕上,然后在完成之后结束脚本。我试图使用与以下代码等效的代码,但我不明白为什么我要进行回溯。

执行时:

1
2
3
4
5
try:
    1 / 0
except ZeroDivisionError:
    print("Exception: ZeroDivisionError")
    raise Exception

控制台读取:

1
2
3
4
5
6
7
8
9
10
11
12
Exception: ZeroDivisionError
Traceback (most recent call last):
  File"<pyshell#19>", line 2, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File"<pyshell#19>", line 5, in <module>
    raise Exception
Exception

我想如果我抓到了ZeroDivisionError,它就不会再被提升了,唯一能显示的就是我最后做的raise Exception,但都会显示在控制台上。

为什么它们都会显示,以及如何更改代码以便只显示第二个,或者是否有更好的方法来实现我想要的?


控制台在这里显示上下文;当从异常处理程序引发异常时,python将活动异常附加为__context__属性,如果不处理新的异常,python稍后将显示该上下文。如果您不希望显示上下文,则需要提供一个原因;您可以向raise ... from None提供一个空原因:

1
2
3
4
5
try:
    1 / 0
except ZeroDivisionError:
    print("Exception: ZeroDivisionError")
    raise Exception from None

引用raise声明文件:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed[...]

A similar mechanism works implicitly if an exception is raised inside an exception handler: the previous exception is then attached as the new exception’s __context__ attribute[...]

从例外文件中:

When raising (or re-raising) an exception in an except clause __context__ is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.

When raising a new exception (rather than using a bare raise to re-raise the exception currently being handled), the implicit exception context can be supplemented with an explicit cause by using from with raise:

1
raise new_exc from original_exc

The expression following from must be an exception or None. It will be set as __cause__ on the raised exception. Setting __cause__ also implicitly sets the __suppress_context__ attribute to True, so that using raise new_exc from None effectively replaces the old exception with the new one for display purposes (e.g. converting KeyError to AttributeError), while leaving the old exception available in __context__ for introspection when debugging.

The default traceback display code shows these chained exceptions in addition to the traceback for the exception itself. An explicitly chained exception in __cause__ is always shown when present. An implicitly chained exception in __context__ is shown only if __cause__ is None and __suppress_context__ is false.