首页 > Python笔记 阅读数:14

Python异常处理(try except finally)

在高级语言(如 C++、Java)中,通常都内置了一套“try...except...finally...”的三步走式错误处理机制,Python 也不例外。

如果我们认为某个代码块可能会出错,就可以用 try 来“管辖”这段代码。一旦发生异常,则不会继续执行后续代码,而是直接跳转至异常处理代码(即 except 语句块),执行 except。如果 try 代码块没有异常发生,则忽略 except 子句。一个 try 代码块中可能包含多个 except 子句,可分别处理不同类型的异常,但最多只有一个分支会被执行。

异常处理过程中如果还有 finally 语句块,则还需执行 finally 语句块。finally 语句块为可选项,非必需,一旦设置,无论是否发生异常,就如其名称所彰显的含义一般,程序“最终”都要在 finally 语句块上“走一遭”,如图 1 所示。

异常处理的三步走
图 1:异常处理的三步走

下面我们以处理“除数为零”这类异常为例,来说明异常处理的三步走流程,如例 1 所示。

【例 1】除数为零的异常处理(exception-zero.py)
def this_fails():
    x = 1/0
try:
    this_fails()
except ZeroDivisionError as err:
    print('运行时异常:',err)
finally:
    print ("我是来演示的,非必需!")
print("我是正常代码!")
程序执行结果为:

运行时异常: division by zero
我是来演示的,非必需!
我是正常代码!


如前所述,凡是涉及管辖范围的,管辖者(如这里的 try 和 except)都要以冒号:来彰显自己的“势力范围”,而被管辖者则要以统一的缩进来表示服从。如第 04 行属于第 03 行的管辖范围。类似地,第 06 行属于第 05 行的管辖范围,下同。

如果我们将第 02 行修改为 x = 1/1,此时代码正常,不会触发异常,但是第 07 行 finally 所管辖的第 08 行也会输出。这是因为,finally 代码块是必定要执行的,而不管 try 代码块有没有异常。

第 09 行语句虽然简单,但它能正常输出也表明了异常处理的意义。因为如果没有前面的异常处理,我们的 Python 程序是脆弱的,稍有风吹草动,整个程序都会受到牵连,随后的程序均无以为继,进而停止运行,这对大型程序而言是难以承受之重。所以说,异常处理能大大提升整个程序的“鲁棒性”(Robust,也称健壮性)。

有时,我们还会有这样的需求:系统给定的异常处理类型不够用,我们能否设计并抛出个性化的异常呢?答案是,当然可以。这时我们可以利用 raise(举起)来抛出一个自定义的异常。此处 raise 的功效基本上和 C++、Java 中的 throw(抛出)是相同的。

示例代码如下:
In [5]: x = 10
In [6]: if x > 5:
   ...:     raise Exception('x 应该小于 5.当前值为:{}'.format(x))

运行上述语句,我们会收到如下的异常信息。

Exception   Traceback (most recent call last)
<ipython-input-42-5feba8c996e1> in <module>
    1 x = 10
    2 if x > 5:
---->3    raise Exception('x 应该小于 5.当前值为:{}'.format(x))
Exception: x 应该小于 5.当前值为:10

相关文章