【Python】(异常机制)raise ... 和 raise ... from ... 的区别和使用

Overview

    • raise ... 和 raise ... from ... 的区别
    • 使用
    • 总结
    • Reference



raise … 和 raise … from … 的区别

  • Python 中 raise 和 raise/from 的区别

raise …:

During handling of the above exception, another exception occurred:

raise … from …:

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


使用

没有 from 是接近错误的使用方式。

比如:

try:
    raise IndexError("in try")
except IndexError as err:
    raise RuntimeError(str(err))

与:

def hanlder_error():
    raise RuntimeError("error by accident")

try:
    raise IndexError("in try")
except IndexError as err:
    hanlder_error()
    raise RuntimeError(str(err)) from err

这是两段有着不同含义的代码。

运行结果对比:
【Python】(异常机制)raise ... 和 raise ... from ... 的区别和使用_第1张图片

不看错误提示消息中的代码的话,“字面上”是一个意思。

删掉错误提示的代码之后,提示信息除了有指出第二个 error 发生的所在位置(在函数里面)之外,提示信息的含义完全一样:

【Python】(异常机制)raise ... 和 raise ... from ... 的区别和使用_第2张图片
这个提示信息的含义都表示:第二个异常是在 except /捕获异常 内部(再次)发生了异常(During handling of the above exception, another exception occurred)。

但是实际情况是:

  • 第二段代码确实符合提示的错误信息(RuntimeError 是在捕获 IndexError 异常处理时另外发生的异常)。

  • 第一段完全不是,第一段代码的第二异常并非是在捕获异常内部(except 中)再次发生异常,而本意是想将 try 内发生的异常(通过另外一种异常类来表示)向更高级调用抛出。

如果使用 raise ... from ... 则错误提示消息含义完全不同:

try:
    raise IndexError("in try")
except IndexError as err:
    raise RuntimeError(str(err)) from err

【Python】(异常机制)raise ... 和 raise ... from ... 的区别和使用_第3张图片

当我们看到 The above exception was the direct cause of the following exception 则知道,这句话下面的异常本质上和这句话上面的异常是同一个。这句话下面的异常加上这句话本身表示了该异常来自 try 内部,而非 except 内。

During handling of the above exception, ... 这句表示了这句话下面的异常来自 except 内;即真正意思是表示了此时发生两个异常

所以我们需要使用 raise ... from ... 这样的写法,如果 except 内部真的没有异常发生的话,错误提示也是表达了只有一个异常,这个异常进一步回溯到 try 内部发生的异常。
raise ... 这么直接编写的话,虽然在代码作用上没有什么差别,但是含义上有区别,它表示了 try 内部发生了异常,但是在 except 内部处理的时候,又发生了另一个异常;这和实际情况是不符合的。



总结

raise 本身就是抛出异常的作用(含义)。

所以当我们想要在 except 内部抛出另外一个异常,就使用 raise

但是如果我们想要将原本来自 try 内部的异常,在 except继续(往上)抛出的话,要嘛直接使用 raise,即:

try:
    raise IndexError("in try")
except IndexError as err:
    ...do something...
    raise

又或者我们想要对这个异常换一种异常类(换一种表示异常含义,比如自己定义的异常类等),
那么就应当使用 raise ... from , 即:

try:
    raise IndexError("in try")
except IndexError as err:
    ...do something...
    raise RuntimeError("the right way to continue raise") from err


Reference

  • Python “raise from” usage
  • PEP 3134 – Exception Chaining and Embedded Tracebacks


你可能感兴趣的:(#,Python)