本篇,我们说说 Python 中的错误处理机制(Error Handler)。
错误处理
与其他语言一样,Python 也提供了 try…except…finally… 的错误处理机制。
try
try:     print('try...')     r = 10 / 0     print('result:', r) except ZeroDivisionError as e:     print('except:', e) finally:     print('finally...') print('END')
 
  | 
 
当我们认为某些代码可能会出错时,就可以用 try 来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即 except 语句块,执行完 except 后,如果有 finally 语句块,则执行 finally 语句块,至此,执行完毕。另外,还可以有多个 except 来捕获不同类型的错误: 
try:     print('try...')     r = 10 / int('a')     print('result:', r) except ValueError as e:     print('ValueError:', e) except ZeroDivisionError as e:     print('ZeroDivisionError:', e) finally:     print('finally...') print('END')
 
  | 
 
此外,如果没有错误发生,可以在 except 语句块后面加一个 else,当没有错误发生时,会自动执行 else 语句: 
try:     print('try...')     r = 10 / int('2')     print('result:', r) except ValueError as e:     print('ValueError:', e) except ZeroDivisionError as e:     print('ZeroDivisionError:', e) else:     print('no error!') finally:     print('finally...') print('END')
 
  | 
 
Python 的错误其实也是 class,所有的错误类型都继承自 BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还会捕获子类错误: 
try:     foo() except ValueError as e:     print('ValueError') except UnicodeError as e:     print('UnicodeError')
 
  | 
 
第二个 except 永远也捕获不到 UnicodeError,因为 UnicodeError 是 ValueError 的子类,如果有,也被第一个 except 给捕获了。
抛出错误
因为错误是 class,捕获一个错误就是捕获到该 class 的一个实例。Python 的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。
class FooError(ValueError):     pass
  def foo(s):     n = int(s)     if n==0:         raise FooError('invalid value: %s' % s)     return 10 / n
  foo('0')
 
  | 
 
只有在必要的时候才定义我们自己的错误类型。如果可以选择 Python 已有的内置的错误类型(比如 ValueError,TypeError),尽量使用 Python 内置的错误类型。
最后,我们来看另一种错误处理的方式: 
def foo(s):     n = int(s)     if n==0:         raise ValueError('invalid value: %s' % s)     return 10 / n
  def bar():     try:         foo('0')     except ValueError as e:         print('ValueError!')         raise
  bar()
 
  | 
 
在 bar() 函数中,我们明明已经捕获了错误,但是,打印一个 ValueError! 后,又把错误通过 raise 语句抛出去了,捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。
raise 语句如果不带参数,就会把当前错误原样抛出。此外,在 except 中 raise 一个 Error,还可以把一种类型的错误转化成另一种类型。