raise与raise······from

在python中,如果想手动引发一个异常,我们一般都会使用raise

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    raise RuntimeError("error occurred")
"""
Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 5, in <module>
    1 / 0
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 7, in <module>
    raise RuntimeError("error occurred")
RuntimeError: error occurred
"""

如果这样设置异常的话,During handling of the above exception, another exception occurred:,我们只是看到提示:在处理以上异常的时候,另一个异常产生了。如果我们使用raise .....from...的语法呢?

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    raise RuntimeError("error occurred") from e
"""
Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 5, in <module>
    1 / 0
ZeroDivisionError: division by zero

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

Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 7, in <module>
    raise RuntimeError("error occurred") from e
RuntimeError: error occurred
"""

The above exception was the direct cause of the following exception:,会直接告诉我们上面异常是下面异常产生的直接原因。

因此我们可以看到两者的不同之处,from会为异常设置一个__cause__属性,表示异常是由谁直接引起的。处理异常的时候出现了新的异常,在不使用from的情况下,更倾向于新异常和旧异常之间没有关联,而from则是能够直接指出新异常是由旧异常直接引起的。这样的话,有助于对异常的分析和排查。但是from有个限制,那就是后面必须跟一个异常的类、或者实例、或者None

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    raise RuntimeError("error occurred") from 123
"""
    raise RuntimeError("error occurred") from 123
TypeError: exception causes must derive from BaseException
"""
# 提示我们必须from一个BaseException
# 这个BaseException是Exception的父类,Exception继承自BaseException
# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    raise RuntimeError("error occurred") from IndexError
"""
    raise RuntimeError("error occurred") from 123
TypeError: exception causes must derive from BaseException
"""
# 这里是ZeroDivisionError,我可以手动用IndexError引发

但如果我在finally中引发异常

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    pass

finally:
    raise Exception("xxxx")
"""
Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 10, in <module>
    raise Exception("xxxx")
Exception: xxxx
"""

可以看到只出现了我们自己引发的异常,于是我们可以设置一个traceback

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    import sys
    tb = sys.exc_info()[2]
finally:
    raise Exception("xxxx").with_traceback(tb)
"""
Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 10, in <module>
    raise Exception("xxxx").with_traceback(tb)
  File "C:/Users/satori/Desktop/satori/task.py", line 5, in <module>
    1 / 0
Exception: xxxx
"""

通过这种方式,会自动帮我们定位到出现异常的语句。这里trackback就是引发异常语句的异常的trackback

我们目前一直在关联异常,那么可不可以禁止异常关联呢?显然是可以的。

# -*- coding:utf-8 -*-
# @Author: WanMingZhu
# @Date: 2019/10/22 10:31
try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception("xxxx") from None
"""
Traceback (most recent call last):
  File "C:/Users/satori/Desktop/satori/task.py", line 7, in <module>
    raise Exception("xxxx") from None
Exception: xxxx
"""

只显示了我们自己定义的异常,没有出现During handling of the above exception, another exception occurred:这样的字眼了。

因此在异常处理中,python会为异常设置上下文。但我们也可以手动通过with_traceback()来设置上下文,或者通过from来指定异常是由谁引起的。这些手段都是为了得到更好的异常回溯信息,打印清晰的异常上下文。若忽略上下文,则可以通过raise ···· from···None来禁止自动显示异常上下文。

猜你喜欢

转载自www.cnblogs.com/traditional/p/11719091.html