Python从入门到精通(十六)Python异常机制2,正确使用Python异常机制的姿势是啥

Posted 码农飞哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python从入门到精通(十六)Python异常机制2,正确使用Python异常机制的姿势是啥相关的知识,希望对你有一定的参考价值。

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦
本文主要介绍Python自定义异常以及如何正确使用Python的异常机制
干货满满,建议收藏,需要用到时常看看。 小伙伴们如有问题及需要,欢迎踊跃留言哦~ ~ ~。

前言

上一篇文章我们介绍了Python的异常机制,但是还没有讲全。这篇文章将继续讲解本文将重点侧重于介绍自定义异常以及正确使用异常机制。

raise用法

有时候我们自定义了一个业务异常类,当触发该异常时将该异常抛给其调用者。又或者当我们捕获到一个未知异常时,需要将该异常封装并抛给其调用者。这时候就可以使用raise关键字了。其语法结构是:

raise [exceptionName [(reason)]]

其有三种用法:

  1. raise: 单独一个raise。该语句引发当前上下文中捕获的异常(比如except块中)或默认引发RuntimeError异常。
  2. raise异常名称:raise后带一个异常类名称,表示引发执行类型的异常。
  3. raise异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
try:
    a = input("输入一个数:")
    # 判断用户输入的是否为数字
    if (not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:", repr(e))

当输入一个字母或者汉字时就会抛出ValueError异常。
当然也可以在except中使用raise,将异常重新抛出。

获取异常的详细信息

在实际开发调试程序中,有时只是获取异常的类型是远远不够的,还需要更详细的信息。这里有两种方式可以实现:

  1. 使用sys模块中的exec_info方法,以元组的形式将当前异常信息返回,该元组中包含3个元素,分别是type,value和traceback。其中:type: 异常类型的名称,他是Exception的子类;value: 捕获到的异常实例;traceback:是一个traceback对象。
  2. 使用taceback模块,后面的章节会介绍到。
import sys

try:
    a = 1 / 0
except:
    print(sys.exc_info())

运行结果是:(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x7fb6438cd300>)。这里详细的打印出了异常类型的名称和实例。

traceback模块

traceback模块用于打印异常的堆栈,因为在实际开发中涉及的调用层次很多,只打印一个异常类型的名称是不够的。使用traceback模块查看异常传播的轨迹,首先需要引入traceback模块,该模块提供了如下两个方法:

  1. traceback.print_exc():将异常传播轨迹信息输出到控制台或者指定文件中。
  2. format_exc():将异常传播轨迹信息转换成字符串。
    如下代码:自定义了一个异常类MyException。main方法调用了firstMethod方法,firstMethod方法调用了secondMethod方法,secondMethod方法调用了thirdMethod方法。而在thirdMethod中抛出了MyException这个异常。
import traceback
class MyException(Exception):
    pass


def thirdMethod():
    raise MyException("自定义异常信息")


def secondMethod():
    thirdMethod()


def firstMethod():
    secondMethod()


def main():
    firstMethod()


try:
    main()
except:
    # 捕获异常,并将异常传播信息输出控制台
    traceback.print_exc()
    # 捕获异常,并将异常传播信息输出制定文件中
    traceback.print_exc(file=open("log.txt", "a"))

运行结果是:

Traceback (most recent call last):
  File "/Volumes/development/Python_learn/PycharmProjects/python_demo_1/demo/error/traceback_test.py", line 31, in <module>
    main()
  File "/Volumes/development/Python_learn/PycharmProjects/python_demo_1/demo/error/traceback_test.py", line 27, in main
    firstMethod()
  File "/Volumes/development/Python_learn/PycharmProjects/python_demo_1/demo/error/traceback_test.py", line 23, in firstMethod
    secondMethod()
  File "/Volumes/development/Python_learn/PycharmProjects/python_demo_1/demo/error/traceback_test.py", line 19, in secondMethod
    thirdMethod()
  File "/Volumes/development/Python_learn/PycharmProjects/python_demo_1/demo/error/traceback_test.py", line 15, in thirdMethod
    raise MyException('自定义异常信息')
MyException: 自定义异常信息

从运行结果可以清晰的看出整个异常传播链,一般排查问题的话,我们可以直接从最下面开始排查,即从最后打印异常的地方开始定位问题。就像上面直接找到raise MyException(‘自定义异常信息’) 。然后定位到问题点出在了traceback_test.py文件的第15行。

自定义异常类及其用法

Python同样是支持自定义异常类的。由于大多数Python内置异常的名字都是以“Error”结尾,所以在实际命名时尽量跟标准的异常命名一样。自定义一个异常类,通常应继承自Exception类(直接继承),当然也可以继承自本身就是从Exception类继承而来的类比如IndexError类。需要说明的是:不建议直接继承BaseException类,因为它是为系统退出异常而保留的。假如直接继承BaseException,可能会导致自定义异常不会被捕获,而是直接发送信号退出程序运行,脱离了我们自定义异常类的初衷。如下就是定义了一个名为BusinessError的异常类,该类直接继承自Exception类,并且重写了其构造方法,传入了指定的msg参数。

class BusinessError(Exception):
    # 自定义异常类型的初始化
    def __init__(self, msg):
        self.msg = msg
        # 返回异常类对象的说明信息
    def __str__(self):
        return ("{} 打印出来".format(repr(self.msg)))


try:
    raise BusinessError("业务出现异常了")
except BusinessError as e:
    print("错误是{}".format(e))

运行结果是:错误是'业务出现异常了' 打印出来

正确使用Python异常处理机制

Python异常处理机制很有用但是不能滥用。劲酒虽好,可不能贪杯哦。使用Python异常处理机制的目标是:

  1. 是程序代码混乱最小化。
  2. 捕获并保留诊断信息
  3. 采用合适的方式结束异常活动。
    根据目标得出使用异常机制需要注意的三点是:

不要过度使用异常

对于一些完全已知的错误和普通错误(比如参数缺失),应该直接编写处理这种错误的代码,返回给前端或者不让程序进行到下一步。就像下面,在遍历列表时通过捕获异常来避免问题。

my_list = ['hello', 'python', 'java']
try:
    i = 0
    while True:
        print(my_list[i])
        i = i + 1
except:
    pass

这样的处理大可不必,因为indexError的异常完全可以通过编码的方式来避免。而不是任其抛出异常。

i = 0
while i < len(my_list):
    print(my_list[i])
    i = i + 1

不要使用过于庞大的try块

好多小伙伴,喜欢一个try走天下。一个几百行的代码在最外层套一个try except语句。其实这样是很不优雅的。因为如果try块里的代码过于庞大业务过于复杂的话,就会造成try块中出现异常的可能性大大增加,从而导致排查异常原因的难度也大大增加。因为可能会存在许多种异常。
正确的做法是:把大块的try块分割成多个可能出现异常的程序段落,并把它们放在单独的try块中,从而分别捕获并处理异常。

不要忽略捕获到的异常

捕获异常之后不能简单的pass或者打印简单的异常信息,最好是对异常进行适当的修复或者提示用户重新操作,如果修复不了的话可以抛到上一层。

总结

本文详细介绍了Python的异常机制。异常很好用,但是不要滥用哦。

Python知识图谱

为了更好帮助更多的小伙伴对Python从入门到精通,我从CSDN官方那边搞来了一套 《Python全栈知识图谱》,尺寸 870mm x 560mm,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,有兴趣的小伙伴可以了解一下------扫描下图中的二维码即可购买。


我本人也已经用上了,感觉非常好用。图谱桌上放,知识心中留。

我是码农飞哥,再次感谢您读完本文

以上是关于Python从入门到精通(十六)Python异常机制2,正确使用Python异常机制的姿势是啥的主要内容,如果未能解决你的问题,请参考以下文章

ROS从入门到精通系列(二十六) 标准化ROS代码风格 - . Python 风格指南

ROS从入门到精通系列(二十六) 标准化ROS代码风格 - . Python 风格指南

ROS从入门到精通系列(二十六) 标准化ROS代码风格 - . Python 风格指南

❤️Python从入门到精通(二十六)用Python的PIL库(Pillow)处理图像真的得心应手❤️

❤️Python从入门到精通(二十六)用Python的PIL库(Pillow)处理图像真的得心应手❤️

Python从入门到精通(十五)Python异常机制,给代码加上安全TAO,不放过一个异常