python异常处理

python学习笔记之异常处理

异常处理

错误与异常

错误:通常指程序运行中不可恢复的问题

异常:通常指可以在程序运行时恢复的问题

异常处理的一般语法:

1
2
3
4
5
6
try: (1)
block
except ExceptionClass as e: (2)
pass
finally: (3)
pass
  1. 异常处理以try开始
  2. 当异常发生时按照一定的规则执行except块,可以存在多个except
  3. 可选的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
2
3
4
5
6
7
8
try:
print('start')
3/0
print('end')
except ZeroDivisionError as e:
print(e)
finally:
print('finally')
start
division by zero
finally

上边代码中人为加入了两个print语句是为了看清代码的执行流程。解释器当执行到3/0时,会抛出上边的ZeroDivisionError异常,此时解释器就不会在执行try语句中的print('end')语句了,而是被except语句捕捉到,执行此代码块中的语句print(e),这里的e是一个变量,表示把异常的信息保存到这个变量上,这是一个可选择参数,如果没有as e,那异常信息就不会被保存。最后再执行了finally代码块中的语句。

except代码是一个类型匹配的过程,可以允许多次出现,但要注意匹配的顺序,如下:

1
2
3
4
5
6
try:
3/0
except Exception:
print('Exception')
except ZeroDivisionError:
print('ZeroDivisionError')
Exception

3/0不是会抛出ZeroDivisionError的异常吗?这里怎么没有被捕捉到,而是被except Exception:语句捕捉到了?这是因为异常在python也是一个class,决大多数的异常都是在Exception类中的,ZeroDivisionErrorException的子类,所以在实际编码中,当有多个except语句时应该把子类放在前面,父类写在后边。

如果except后边不接任何类名,表示可以捕捉任何的异常信息。

再来看一下finally语句,它在异常处理中不管是否捕捉到异常,finally语句都会被执行,以下边的例子说明:

1
2
3
4
5
6
7
8
9
10
def p():
print('call p function')

def main():
try:
return p()
finally:
print('finally...')

main()
call p function
finally...

main函数中有一个return语句,执照常理来说,在一个函数中执行return语句时,此函数就执行结束了,但这里为什么还会执行finally语句呢?

执行流程大致是这样的:

当解释器执行到return p()语句时,先调用p函数,输出了call p function,接着并没有把结果return回去,而是把此时的状态保存起来后去执行finally语句,执行完成后把之前保存的状态恢复后再执行return操作,这样就成上边调用main函数的输出信息了。

抛出异常

抛出异常使用raise语句

1
2
3
4
5
def fn(i):
if i < 0:
raise Exception('i < 0')

fn(-4)
---------------------------------------------------------------------------

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
2
3
4
5
6
7
def fn():
3/0

def main():
fn()

main()
---------------------------------------------------------------------------

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
2
3
4
try:
main()
except Exception as e:
print(e)
division by zero

自定义异常

自定义异常:当一个类继承自Exception类或其派生类时。

1
2
class MyException(Exception):
pass
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
2
3
4
try:
raise MyException('exception')
except MyException as e:
print(e)
exception
文章目录
  1. 1. 异常处理
    1. 1.1. 错误与异常
    2. 1.2. 抛出异常
    3. 1.3. 未处理异常
    4. 1.4. 自定义异常
|