异常,异常处理和类

异常

程序执行中引发的任何异常都是某个类的实例,也就是说,异常都是类。

Python 定义了一批内部异常,也允许写程序的人定义自己的异常。基础异常类(所有异常的基类)是内部类 BaseException,所有的内部异常类都有由其子类 Exception 的(直接或间接的)派生类,自定义的异常类也应该从这个类(或者其子类)派生。

引发一个异常(无论是系统内部自动引发,还是由于执行了 raise 语句而引发),就是生成了相应异常类的一个实例对象,并将其送给解释器的异常处理机制,使之按规则传播。

在 try 语句的 except 段的关键字 except 后面列出的异常名(异常名列表),每个名字是一个异常类的名字,表示这个 except 段处理相关程序段的执行中发生的属于这个类的异常(实例)。

由于类之间有继承结构,如果某个异常处理段要求捕捉并处理相应 try 段执行中出现的属于基类 EB 的异常,而 EC 是由 EB 的直接或间接派生类,那么这个异常段也将捕捉执行中发生的 EC 异常(如果前面没有其他异常段处理 EC 异常)。进一步说,如果一个异常段捕捉 Exception 异常,那么它就会捕捉所有的内部定义异常和用户自定义异常,因为这些异常都是 Exception 类的派生类。

内部定义异常

Python 系统内部异常的详细情况见标准库手册第 5 节,特别是 5.4 节给出了所有内部异常的层次结构。

自定义异常

自定义异常就是定义 Exception 类的派生类。除了必须用 Exception 或者其派生类作为基类外,定义表示异常的类也就是定义一个类,所有前面讨论的有关类定义的机制和结构都可以使用。当然,定义异常类不是为了保存程序的正常计算中需要用的数据,而是为了在适当的场合作为异常去引发。具体定义是编程问题,这里不讨论。

raise语句

前面介绍过,异常引发语句 raise(语言手册7.8节)的基本语法是
	raise 表达式
如果没给出 "表达式" 部分,该语句的执行将引发当时正在处理的那个异常。显然这种 raise 语句只能出现在异常处理器内部(因为只有这时才有 "正在处理的异常"),否则语句执行时就会报错。如果给出了 "表达式",其值应该是某个异常类的名字或者异常类的对象。"表达式" 的最简单情况是一个异常类名,表示要求生成这个异常类的实例(异常)。

raise 语句还有一个更复杂的形式

	raise 表达式 from 表达式
这里的 from 也是一个关键字,from 段里的表达式的值也应该是一个异常类或异常类的对象。这个语句的执行也引发前一 "表达式" 表示的异常,但还把后一表达式的值附加在生成的异常里,作为其 __cause__ 属性的值。如果有异常处理器捕捉到这个异常,就可以通过这个属性取出相关的信息,在处理时使用。

注意,在 raise 语句里直接写一个异常类名,求值得到这个异常类的实例对象。换一个方式,如果 myExcept 是一个异常类,调用表达式 myExcept() 也是生成一个异常对象,因此也可以用在这里。进一步说,如果在这是我们自己定义的异常类,其中定义了 __init__ 函数,而且它有除除 self 之外的参数,那么就可以在相应的 raise 语句里写带实参的异常实例生成表达式,通过这种方式,可以把 raise 语句所在位置可以得到的任意有用的信息包装在异常对象里,送到相应的异常处理器去。

如前所述,要使用捕捉到的异常(进而使用其中包装的信息),需要在 except 段头部的异常名或异常名元组之后加一个 as 段,指定一个变量:

	except 异常 as 变量
在随后的异常处理器代码里,就可以通过这个变量访问异常里的信息了。这个变量是这个处理器的局部变量,其作用域就是处理器的代码体。
本页及相关页面(除另声明者外)由裘宗燕创建维护,可自由用于各种学习活动。其他使用需得到作者许可。