4.9 异常处理语句try

在Python中,程序的运行过程被分为两种状态,正常和异常。正常状态就是程序运行没有出错的状态,在大部分情况下,程序都是处于正常状态, 当然也会有程序运行时发生意料之外的错误的情况,这被称作异常状态。当异常发生时,程序会被停止并报错,例如在4.2.2小节中, 我们试图对字符串中的字符进行修改,会得到以下的错误提示:

1
2
3
4
>>> "1234"[0] = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

该异常的类型为TypeError,除了该类型外,Python内置的异常类还有很多,下表中列出了部分常见的异常类型:

../_images/部分异常类型.png

图4-20 部分异常类型

4.9.1 捕获异常try/except

尽管异常可以提示程序中的存在的错误,但它也会导致程序停止运行。如果我们既想知道哪里发生了错误,又不想程序停止运行,该怎么办? 在Python中存在异常处理语句try/except可以用于捕获并处理异常状态,它会告诉Python当异常发生时,该执行什么程序, 下面以捕获异常类型中的TypeError为例,介绍try/except语句:

1
2
3
4
5
6
>>> try:
...   "Hello World!"[0] = 1
... except TypeError:
...   print("String cannot be modified!")
...
String cannot be modified!

将需要捕获异常的语句放在try语句内部的语句块中,当异常发生时,用except语句捕获该异常,并执行except语句内部的语句块。 这里需要注意的是,except后的异常名称应与try语句块产生的异常名称相同。可以看到,使用try/except语句可以对异常进行捕获, 避免了程序停止运行的情况发生。

还可以使用多个except来分别处理try语句的各个异常情况:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> data = [0,'a']
>>>
>>> for i in data:
...     try:
...       print(1/i)
...     except TypeError:
...       print("TypeError!")
...     except ZeroDivisionError:
...       print("ZeroDivisionError!")
...
ZeroDivisionError!
TypeError!

在该程序中,定义了data列表,在列表内有两项,0和’a’,依次作为第5行除法运算中的除数。显然,这两个数据无法作为除数使用, 会分别引起除数为零和数据类型错误这两个异常。

也可以将多种异常情况放在同一个except子句中,将上例程序中的两个except合为一个:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> data = [0,'a']
>>>
>>> for i in data:
...     try:
...       print(1/i)
...     except (TypeError, ZeroDivisionError):
...       print("Error!")
...
Error!
Error!

在这里需要注意except后多个异常之间以“,”隔开,并用“( )”将它们包括在一起。

4.9.2 else

在有些时候,当try内的语句块未发生异常时,我们需要执行某一语句块,与if中的else一样,在try/except后也可以添加else子句。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> data = [list('Hello World!'),"Hello World!"]  #list('Hello World!') => ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']

>>> for i in data:
...     try:
...         i[0] = 2
...     except TypeError:
...         print("String cannot be modified!")
...     else:
...         print("List can be modified!")
...
List can be modified!
String cannot be modified!

在该程序中,先是新建了一个data列表,内部有两项,分别为列表list(‘Hello World!’)和字符串”Hello World!”,下面通过一个for循环依次遍历data列表, 将data列表中的两项送入try中进行检验。被检验的第一项是列表,第二项是字符串,从而得到两行输出结果。 从该程序的输出结果中可以得出,当try内的语句块产生异常时,执行except内的语句块程序,未发生异常时,执行else内的语句块程序。

4.9.3 finally

最后是finally子句,它被放在try/except/else的最后,无论try中的语句是否发生异常,都会执行finally内的语句块。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
>>> data = [list('Hello World!'),"Hello World!"]
>>>
>>> for i in data:
...     try:
...         i[0] = 1
...     except TypeError:
...         print("String cannot be modified!")
...     else:
...         print("List can be modified!")
...     finally:
...         print("I'll always be here.")
...
List can be modified!
I'll always be here.
String cannot be modified!
I'll always be here.

该程序与4.9.2中的相似,只是在程序的最后加上了finally子句。 从输出结果可以看到,由于try语句执行了两次,因此finally子句内的语句块程序也被执行了两次,可以看出, finally子句的执行与try内是否发生异常无关。

4.9.4 小结

本节罗列了Python中常见的一些异常情况,并介绍了如何使用try/except/else/finally语句对异常进行捕获和处理。

下一节中将介绍如何使用函数将一个语句块抽象为一个代码,这可以减少重复编程以及提高程序的可读性。