最近我正在阅读有关异常链接的内容,我不确定何时应该使用此语法以及出于什么原因。
我已经习惯了这样的模式:
try:
my_function()
exception MyError:
my_logger.exception("Error occured")
raise MyProcessError("Process failed")
我注意到,如果我在此处使用异常链接,则回溯中的一个文本将被更改,并且 MyProcessError 将具有包含来自 MyError 的消息的新属性。
try:
my_function()
exception MyError as err:
my_logger.exception("Error occured")
raise MyProcessError("Process failed") from err
跟踪日志中提及的更改是将“在处理上述异常期间,发生了另一个异常”替换为“上述异常是以下异常的直接原因”。
那么使用这种语法的原因是什么?我什么时候应该将其包含到我的代码中? 欢迎举例 :-)
在异常处理程序中,如果您显式引发异常,您将需要使用
from err
或 from None
(取决于抑制原始回溯是否更有意义)。
如果没有
from
,您收到的消息:“在处理上述异常期间,发生了另一个异常”,表明“出现了问题,然后,在尝试从中恢复时,出现了其他问题(可能不相关)。这例如,当您输入错误 (my_logger.expeption("Error occurred")
) 或尝试将某些内容保存到无法打开的文件时,就会出现这种情况。
带有
from
,它表明只有一件事出了问题,即您没有处理自己,但您有一些对程序员或用户有用的更多信息。例如,您可以捕获 KeyError
并引发不同的异常,并显示消息“尝试编辑不存在的小部件”或其他内容。
因此,
raise SomeException("some description") from err
是一种能够解释如果引发err
的代码无法做到这一点(因为它来自标准库,或者因为它缺乏必要的上下文)的方法。被调用),而不会让用户认为两个独立的事情接连发生了错误。
声明
raise EXCEPTION from CAUSE
相当于:
exc = EXCEPTION
exc.__cause__ = CAUSE
raise exc
此功能有时对于存储有关异常链的信息以便在最后一级进行处理、传输或记录非常有用。
例如,在创建我们自己的库时,我们使用基类创建自己的异常层次结构,并且我们不想从我们的函数中抛出第三个库的异常。但同时,我们希望将原始异常的信息保存为详细信息。
class ThirdPartyLibException(Exception):
pass
def third_party_lib_foo():
...
raise ThirdPartyLibException('third party exception')
class MyLibException(Exception):
pass
def my_lib_foo():
try:
third_party_lib_foo()
except ThirdPartyLibException as e:
raise MyLibException() from e
try:
my_lib_foo()
except MyLibException as e:
print('True reason: ', str(e.__cause__))
# processing