Python 提供了try except 语句捕获并处理异常,该异常处理语句的基本语法结构如下:try: 注意,except 后面也可以不指定具体的异常名称,这样的话,表示要捕获所有类型的异常。 另外,从 try except 的基本语法格式可以看出,try 块仅有一个,但 except 代码块可以有多个,这是为了针对不同的异常类型提供不同的异常处理方式。当程序发生不同的意外情况时,会对应不同的异常类型,Python 解释器就会根据该异常类型来决定使用哪个 except 块来处理该异常。通过在 try 块后提供多个 except 块可以无须在异常处理块中使用 if 判断异常类型,但依然可以针对不同的异常类型提供相应的处理逻辑,从而提供更细致、更有条理的异常处理逻辑。 try except 语句的执行流程如下:
事实上,不管程序代码块是否处于 try 块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统总会自动生成一个 Error 对象。如果程序没有为这段代码定义任何的 except 块,则 Python 解释器无法找到处理该异常的 except 块,程序就会停止运行;反之,如果程序发生异常,并且该异常经 try 捕获并由 except 处理完成,则程序会继续执行。 举个例子: try:a = int(input("输入被除数:"))b = int(input("输入除数:"))c = a / bprint("您输入的两个数相除的结果是:", c )except (ValueError, ArithmeticError):print("程序发生了数字格式异常、算术异常之一")except :print("未知异常")print("程序继续运行") 输入被除数:a 除此之外,由于 try 块中引发了异常,并被 except 块成功捕获,因此程序才可以继续执行,才有了“程序继续运行”的输出结果。 访问异常信息如果程序需要在 except 块中访问异常对象的相关信息,可以通过为 except 块添加as a 来实现。当 Python 解释器决定调用某个 except 块来处理该异常对象时,会将异常对象赋值给 except 块后的异常变量,程序即可通过该变量来获得异常对象的相关信息。所有的异常对象都包含了如下几个常用属性和方法:
下面例子演示了程序如何访问异常信息: def foo():try:fis = open("a.txt");except Exception as e:# 访问异常的错误编号和详细信息print(e.args)# 访问异常的错误编号print(e.errno)# 访问异常的详细信息print(e.strerror)foo() 在 Python 的早期版本中,直接在单个异常类或异常类元组(多异常捕获)之后添加异常变量,中间用逗号隔开即可。 上面程序调用了 Exception 对象的 args 属性(该属性相当于同时返回 errno 属性和 strerror 属性)访问异常的错误编号和详细信息。运行上面程序,会看到如下运行结果:(2, 'No such file or directory') 关于如何处理异常的传播轨迹信息,以及使用 open() 方法来打开一个文件,用于读取磁盘文件的内容,后续章节还有更详细的介绍,此处暂不详细讲解。 异常类的继承体系当 Python 解释器接收到异常对象时,如何为该异常对象寻找 except 块呢?注意上面程序中 except 块的 except Exception,这意味着此 except 块专门用来处理该异常类以及其子类的异常实例。当 Python 解释器接收到异常对象后,会依次判断该异常对象是否是 except 块后的异常类或其子类的实例,如果是,Python 解释器将调用该 except 块来处理该异常;否则,再次拿该异常对象和下一个 except 块里的异常类进行比较。 Python 异常捕获流程示意图如图 1 所示: ![]() 图 1 Python 异常捕获流程示意图 从图 1 中可以看出,在通常情况下,如果 try 块被执行一次,则 try 块后只有一个 except 块会被执行,不可能有多个 except 块被执行。除非在循环中使用了 continue 开始下一次循环,下一次循环又重新运行了 try 块,这才可能导致多个 except 块被执行。 Python 的所有异常类都从 BaseException 派生而来,提供了丰富的异常类,这些异常类之间有严格的继承关系,图 2 显示了 Python 的常见异常类之间的继承关系。 ![]() 图 2 Python 的常见异常类之间的继承关系 从图 2 中可以看出,Python 的所有异常类的基类是 BaseException,但如果用户要实现自定义异常,则不应该继承这个基类,而是应该继承 Exception 类。 BaseException 的主要子类就是 Exception,不管是系统的异常类,还是用户自定义的异常类,都应该从 Exception 派生。 下面看几个简单的异常捕获的例子:try: a = int(input("输入被除数:")) b = int(input("输入除数:")) c = a / b print("您输入的两个数相除的结果是:", c )except ValueError: print("数值错误:程序只能接收整数参数")except ArithmeticError: print("算术错误")except Exception: print("未知异常")
上面程序中的异常类型,都是非常常见的运行时异常,读者应该记住这些异常,并掌握在哪些情况下可能出现这些异常。 正如在前面程序中所看到的,程序总是把对应 Exception 类的 except 块放在最后,这是为什么呢?想一下图 1 所示的 Python 异常捕获流程,可能你就会明白,如果把 Exception 类对应的 except 块排在其他 except 块的前面,Python 解释器将直接进入该 except 块(因为所有的异常对象都是 Exception 或其子类的实例),而排在它后面的 except 块将永远也不会获得执行的机会。实际上,在进行异常捕获时,不仅应该把 Exception 类对应的 except 块放在最后,而且所有父类异常的 except 块都应该排在子类异常的 except 块的后面( 即:先处理小异常,再处理大异常)。 虽然 Python 语法没有要求,但在实际编程时一定要记住先捕获小异常,再捕获大异常。 |
|
来自: 星光闪亮图书馆 > 《专题3、Python异常处理机制》