python学习笔记之异常处理
异常处理
错误与异常
错误:通常指程序运行中不可恢复的问题
异常:通常指可以在程序运行时恢复的问题
异常处理的一般语法:
| 1 | try: (1) | 
- 异常处理以try开始
- 当异常发生时按照一定的规则执行except块,可以存在多个except块
- 可选的finally块,无论如何都会被执行,通常用于清理工作
以一个例子来说明,如下:
| 1 | 3/0 | 
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-3-a0641230c7a8> in <module>()
----> 1 3/0
ZeroDivisionError: division by zero
显然,数字0是不能做除数的,这里会抛出ZeroDivisionError错误,程序执行被中止。如果我们想执行3/0时不抛出这样的异常,而是可以人为处理,这时就需要做异常处理了,如下:
| 1 | try: | 
start
division by zero
finally
上边代码中人为加入了两个print语句是为了看清代码的执行流程。解释器当执行到3/0时,会抛出上边的ZeroDivisionError异常,此时解释器就不会在执行try语句中的print('end')语句了,而是被except语句捕捉到,执行此代码块中的语句print(e),这里的e是一个变量,表示把异常的信息保存到这个变量上,这是一个可选择参数,如果没有as e,那异常信息就不会被保存。最后再执行了finally代码块中的语句。
except代码是一个类型匹配的过程,可以允许多次出现,但要注意匹配的顺序,如下:
| 1 | try: | 
Exception
3/0不是会抛出ZeroDivisionError的异常吗?这里怎么没有被捕捉到,而是被except Exception:语句捕捉到了?这是因为异常在python也是一个class,决大多数的异常都是在Exception类中的,ZeroDivisionError是Exception的子类,所以在实际编码中,当有多个except语句时应该把子类放在前面,父类写在后边。
如果except后边不接任何类名,表示可以捕捉任何的异常信息。
再来看一下finally语句,它在异常处理中不管是否捕捉到异常,finally语句都会被执行,以下边的例子说明:
| 1 | def p(): | 
call p function
finally...
在main函数中有一个return语句,执照常理来说,在一个函数中执行return语句时,此函数就执行结束了,但这里为什么还会执行finally语句呢?
执行流程大致是这样的:
当解释器执行到return p()语句时,先调用p函数,输出了call p function,接着并没有把结果return回去,而是把此时的状态保存起来后去执行finally语句,执行完成后把之前保存的状态恢复后再执行return操作,这样就成上边调用main函数的输出信息了。
抛出异常
抛出异常使用raise语句
| 1 | def fn(i): | 
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-3-87e48ca0d898> in <module>()
      3         raise Exception('i < 0')
      4 
----> 5 fn(-4)
<ipython-input-3-87e48ca0d898> in fn(i)
      1 def fn(i):
      2     if i < 0:
----> 3         raise Exception('i < 0')
      4 
      5 fn(-4)
Exception: i < 0
raise Exception('i < 0')语句就是抛出一个自定义异常信息,Exception是类,其实质是抛出了Exception类的一个实例。
未处理异常
异常未处理时会往上层抛出,如果都没有异常处理时会交给python解释器处理,如下:
| 1 | def fn(): | 
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-5-57d9f8a0a6b1> in <module>()
      5     fn()
      6 
----> 7 main()
<ipython-input-5-57d9f8a0a6b1> in main()
      3 
      4 def main():
----> 5     fn()
      6 
      7 main()
<ipython-input-5-57d9f8a0a6b1> in fn()
      1 def fn():
----> 2     3/0
      3 
      4 def main():
      5     fn()
ZeroDivisionError: division by zero
上边的异常信息就一层层的往上层抛出,最后由解释器处理了。如果要在main()捕捉异常呢,如下:
| 1 | try: | 
division by zero
自定义异常
自定义异常:当一个类继承自Exception类或其派生类时。
| 1 | class MyException(Exception): | 
| 1 | raise MyException('exception') | 
---------------------------------------------------------------------------
MyException                               Traceback (most recent call last)
<ipython-input-8-c6b10bf8a778> in <module>()
----> 1 raise MyException('exception')
MyException: exception
MyException类继承自Exception类,所以MyException类是一个自定义异常类,当执行raise MyException('exception')语句时抛出的异常就是自定义的异常类。
捕获自定义异常,如下:
| 1 | try: | 
exception
