Python try except 图片看不了?点击切换HTTP 返回上层
try except
语句捕获并处理异常,该异常处理语句的基本语法结构如下:
try:
可能产生异常的代码块
except [(Error1, Error2, ...) [as e]]:
处理异常的代码块1
except [(Error3, Error4, ...) [as e]]:
处理异常的代码块2
注意,except 后面也可以不指定具体的异常名称,这样的话,表示要捕获所有类型的异常。
另外,从 try except 的基本语法格式可以看出,try 块仅有一个,但 except 代码块可以有多个,这是为了针对不同的异常类型提供不同的异常处理方式。当程序发生不同的意外情况时,会对应不同的异常类型,Python 解释器就会根据该异常类型来决定使用哪个 except 块来处理该异常。通过在 try 块后提供多个 except 块可以无须在异常处理块中使用 if 判断异常类型,但依然可以针对不同的异常类型提供相应的处理逻辑,从而提供更细致、更有条理的异常处理逻辑。
try except 语句的执行流程如下:- 首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常对象,该异常对象会提交给 Python 解释器,此过程被称为引发异常。
- 当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为捕获异常。如果 Python 解释器找不到捕获异常的 except 块,则程序运行终止,Python 解释器也将退出。
事实上,不管程序代码块是否处于 try 块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统总会自动生成一个 Error 对象。如果程序没有为这段代码定义任何的 except 块,则 Python 解释器无法找到处理该异常的 except 块,程序就会停止运行;反之,如果程序发生异常,并且该异常经 try 捕获并由 except 处理完成,则程序会继续执行。
举个例子:
try: a = int(input("输入被除数:")) b = int(input("输入除数:")) c = a / b print("您输入的两个数相除的结果是:", c ) except (ValueError, ArithmeticError): print("程序发生了数字格式异常、算术异常之一") except : print("未知异常") print("程序继续运行")程序运行结果为:
输入被除数:a
程序发生了数字格式异常、算术异常之一
程序继续运行
除此之外,由于 try 块中引发了异常,并被 except 块成功捕获,因此程序才可以继续执行,才有了“程序继续运行”的输出结果。
访问异常信息
如果程序需要在 except 块中访问异常对象的相关信息,可以通过为 except 块添加as a
来实现。当 Python 解释器决定调用某个 except 块来处理该异常对象时,会将异常对象赋值给 except 块后的异常变量,程序即可通过该变量来获得异常对象的相关信息。所有的异常对象都包含了如下几个常用属性和方法:
- args:该属性返回异常的错误编号和描述字符串。
- errno:该属性返回异常的错误编号。
- strerror:该属性返回异常的描述宇符串。
- with_traceback():通过该方法可处理异常的传播轨迹信息。
下面例子演示了程序如何访问异常信息:
def foo(): try: fis = open("a.txt"); except Exception as e: # 访问异常的错误编号和详细信息 print(e.args) # 访问异常的错误编号 print(e.errno) # 访问异常的详细信息 print(e.strerror) foo()从上面程序可以看出,如果要访问异常对象,只要在单个异常类或异常类元组(多异常捕获)之后使用 as 再加上异常变量即可。
在 Python 的早期版本中,直接在单个异常类或异常类元组(多异常捕获)之后添加异常变量,中间用逗号隔开即可。
上面程序调用了 Exception 对象的 args 属性(该属性相当于同时返回 errno 属性和 strerror 属性)访问异常的错误编号和详细信息。运行上面程序,会看到如下运行结果:
(2, 'No such file or directory')
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("未知异常")上面程序针对 ValueError、ArithmeticError 类型的异常,提供了专门的异常处理逻辑。该程序运行时的异常处理逻辑可能有如下几种情形:
- 如果在运行该程序时输入的参数不是数字,而是字母,将发生数值错误,Python 将调用 ValueError 对应的 except 块处理该异常。
- 如果在运行该程序时输入的第二个参数是 0,将发生除 0 异常,Python 将调用 ArithmeticError 对应的 except 块处理该异常。
- 如果在程序运行时出现其他异常,该异常对象总是 Exception 类或其子类的实例,Python 将调用 Exception 对应的 except 块处理该异常。
上面程序中的异常类型,都是非常常见的运行时异常,读者应该记住这些异常,并掌握在哪些情况下可能出现这些异常。
正如在前面程序中所看到的,程序总是把对应 Exception 类的 except 块放在最后,这是为什么呢?想一下图 1 所示的 Python 异常捕获流程,可能你就会明白,如果把 Exception 类对应的 except 块排在其他 except 块的前面,Python 解释器将直接进入该 except 块(因为所有的异常对象都是 Exception 或其子类的实例),而排在它后面的 except 块将永远也不会获得执行的机会。实际上,在进行异常捕获时,不仅应该把 Exception 类对应的 except 块放在最后,而且所有父类异常的 except 块都应该排在子类异常的 except 块的后面( 即:先处理小异常,再处理大异常)。
虽然 Python 语法没有要求,但在实际编程时一定要记住先捕获小异常,再捕获大异常。