Python-异常处理
阅读目录:
1、异常 Exception
2、产生异常
3、异常的捕获
4、异常类及继承层次
5、BaseException及子类
6、Exception 及子类
7、异常的捕获
8、as子句
9、finally 子句
10、异常嵌套
11、else语句
12、异常的捕获时机
13、总结
1、异常 Exception
错误 和 异常的区别:
错误:Error
-
-
- 逻辑错误:算法错误,加法写成了减法
- 笔误:变量名写错了,语法错误
- 函数或类使用错误,其实这也属于逻辑错误
- 总之错误是可以避免的
-
异常:Exception
-
-
- 本意就是意外情况
- 这有个前提,没有出现上面说的错误,也就是说程序写的没问题,但是在某些情况下,会出现一些意外,导致程序无法正常的执行下去
- 例如open函数,操作一个文件,文件不存在,或创建一个文件已经存在,或访问一个网络文件突然断网了,这就是一场,是个意外的情况。
- 异常是不可能避免的
-
错误和异常:
在高级编程语言中一般都有错误和异常的概念,异常是可以捕获,并被处理的,但是错误是不能被捕获的。
举例:
异常:
错误:
总结:
一个健壮的程序
尽可能的避免错误
尽可能的捕获,处理各种异常。
Python的特点是,将Error放到异常类中。
2、产生异常:
产生:
-
- raise 语句显式的抛出异常(手动抛出)
- Python解释器自己检测到异常并引发它
举例:
解释器自动抛出:
手动抛出:
程序会在异常抛出的地方中断执行,如果不捕获,就会提前结束程序(其实是终止当前线程的执行)
raise:
raise 后面什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛类型异常,这种但是很少使用。
raise 后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化
raise IndexError() :无参构造 ----BaseException的派生类
raise IndexError :无参构造 ----BaseException的派生类
raise IndexError('index error') :有参构造 ----BaseException的派生类
3、异常的捕获:
语法:
1 try: 2 待捕获异常的代码块,只要出现一条异常,就会终止,后面的执行,跳到except 3 except [异常类型]: 4 异常的处理代码块
举例:
1:
2:
3:
4、异常类及继承层次:
获取BaseException的子类:
1 def foo(cls, count=0): 2 for i in cls.__subclasses__(): 3 if count == 0: 4 print(count * '\t' + '+-- ' + str(i)) 5 else: 6 print((count - 1) * '\t'+ '|' + '\t' + '+-- ' + str(i)) 7 if i.__subclasses__() : 8 count += 1 9 foo(i, count) 10 else: 11 continue 12 13 14 foo(BaseException)
结果:
1 +-- <class 'Exception'> 2 | +-- <class 'TypeError'> 3 | +-- <class 'StopAsyncIteration'> 4 | +-- <class 'StopIteration'> 5 | +-- <class 'ImportError'> 6 | +-- <class 'ModuleNotFoundError'> 7 | +-- <class 'zipimport.ZipImportError'> 8 | +-- <class 'OSError'> 9 | +-- <class 'ConnectionError'> 10 | +-- <class 'BrokenPipeError'> 11 | +-- <class 'ConnectionAbortedError'> 12 | +-- <class 'ConnectionRefusedError'> 13 | +-- <class 'ConnectionResetError'> 14 | +-- <class 'BlockingIOError'> 15 | +-- <class 'ChildProcessError'> 16 | +-- <class 'FileExistsError'> 17 | +-- <class 'FileNotFoundError'> 18 | +-- <class 'IsADirectoryError'> 19 | +-- <class 'NotADirectoryError'> 20 | +-- <class 'InterruptedError'> 21 | +-- <class 'PermissionError'> 22 | +-- <class 'ProcessLookupError'> 23 | +-- <class 'TimeoutError'> 24 | +-- <class 'io.UnsupportedOperation'> 25 | +-- <class 'EOFError'> 26 | +-- <class 'RuntimeError'> 27 | +-- <class 'RecursionError'> 28 | +-- <class 'NotImplementedError'> 29 | +-- <class '_frozen_importlib._DeadlockError'> 30 | +-- <class 'NameError'> 31 | +-- <class 'UnboundLocalError'> 32 | +-- <class 'AttributeError'> 33 | +-- <class 'SyntaxError'> 34 | +-- <class 'IndentationError'> 35 | +-- <class 'TabError'> 36 | +-- <class 'LookupError'> 37 | +-- <class 'IndexError'> 38 | +-- <class 'KeyError'> 39 | +-- <class 'encodings.CodecRegistryError'> 40 | +-- <class 'ValueError'> 41 | +-- <class 'UnicodeError'> 42 | +-- <class 'UnicodeEncodeError'> 43 | +-- <class 'UnicodeDecodeError'> 44 | +-- <class 'UnicodeTranslateError'> 45 | +-- <class 'io.UnsupportedOperation'> 46 | +-- <class 'AssertionError'> 47 | +-- <class 'ArithmeticError'> 48 | +-- <class 'FloatingPointError'> 49 | +-- <class 'OverflowError'> 50 | +-- <class 'ZeroDivisionError'> 51 | +-- <class 'SystemError'> 52 | +-- <class 'encodings.CodecRegistryError'> 53 | +-- <class 'ReferenceError'> 54 | +-- <class 'MemoryError'> 55 | +-- <class 'BufferError'> 56 | +-- <class 'Warning'> 57 | +-- <class 'UserWarning'> 58 | +-- <class 'DeprecationWarning'> 59 | +-- <class 'PendingDeprecationWarning'> 60 | +-- <class 'SyntaxWarning'> 61 | +-- <class 'RuntimeWarning'> 62 | +-- <class 'FutureWarning'> 63 | +-- <class 'ImportWarning'> 64 | +-- <class 'UnicodeWarning'> 65 | +-- <class 'BytesWarning'> 66 | +-- <class 'ResourceWarning'> 67 | +-- <class 'locale.Error'> 68 | +-- <class 'warnings._OptionError'> 69 +-- <class 'GeneratorExit'> 70 +-- <class 'SystemExit'> 71 +-- <class 'KeyboardInterrupt'>
5、BaseException及子类
BaseException是所有内建异常类的基类
SystemExit
sys.exit() 函数引发的异常,异常不捕获处理,就直接交给Python解释器,解释器退出。
如果except语句捕获了该异常,则继续向后进行,如果没有捕获,解释器直接退出当前执行的程序
Keyboardinterrupt:
对应的捕获用户中断行为 Ctrl+ c
测试:
本地新建一个.py 文件,输入如下代码:
1 try: 2 import time 3 while True: 4 time.sleep(2) 5 print('_________') 6 except KeyboardInterrupt: 7 print('ctrl + c') 8 print('out')
在cmd中执行该文件,可以通过ctrl + c 结束中断。
6、Exception 及子类:
Exception是所有内建的,非系统退出的异常的基类,自定义的异常应该继承他
SyntaxError 语法错误:是无法捕获的,直接识别出来。但在python中是归并到异常类的Exception下的子类
ArithmeticError所有算术引发的异常,其子类有除零异常等。
LookupError:使用映射的键或序列的索引无效时引发的异常的基类:IndexError,KerError
自定义异常:
从Exception继承的类
7、异常的捕获:
except可以捕获多个异常:
总结:
-
- 捕获规则
- 捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块
- 如果被一个except语句捕获,其他except语句就不会再次捕获了
- 如果没有任何一个except语句捕获到这个异常,则该异常就向外抛出
- 捕获原则:
- 从小到大,从具体到宽泛
- 捕获规则
8、as子句:
被抛出的异常,应该是异常的实例 ,如何获得这个对象呢,使用as语句。
上面是因为,调用无参构造器,事实上 是有参,但没有缺省值所以在调用的时候,产生异常。
关于 raise 的问题:
一般文件open的都是关于OsError的异常,一般 as e 这个e实例,送到日志中去。
9、finally 子句:
finally:最终,即最后一定要执行的,try-----finally语句快中,不管是否发生了异常,都要执行finally的部分。
测试:return必须写在try语句结构中,如果在最上面,直接返回,函数调用结束了。
一般不这样做,return不会写到 except,finally中,很少这样操作。
如果没有except,就是任何异常都不管,向外抛。
测试嵌套,以及怎么处理文件句柄清理:
raise用法:
测试1:
测试2:
压制异常:使用return
测试1:
测试2:
10、异常嵌套
11、else语句:
12、异常的捕获时机
1、立即捕获:
需要立即返回一个明确的结果。
也就是说,可能产生异常,如果出现异常,立即处理。
1 def parse_int(s): 2 try: 3 return int(s) 4 except: 5 return 0 6 print(parse_int('s'))
2、边界捕获:
封装产生了边界:
例如:写了一个模块,用户调用这个模块的时候,捕获异常,模块内部不需要捕获,处理异常,一番内部处理了,外部调用者就无法感知了。
例如:open函数,出现的异常交给调用者处理,文件存在了,就用在创建了,看是否修改还是删除。
例如:自己写一个雷,使用open函数,但是出现了异常不知道如何处理,就继续往外层抛,一般来说,最外层也是边界,必须处理这个异常了,否则线程退出。
也就是一句话:提供功能的,就不要捕获异常了,往外抛,让调用者感知到异常。让调用者处理。
13、总结:
try:
<> 运行别的代码
except <异常类>:
<> 捕获某种类型的异常
else:
<> 如果没有发生异常
finally:
<> 退出try 时总会执行
try工作原理:
- 如果try 中语句执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句
- 如果try中语句执行时发生异常,却没有匹配的except子句,异常将被递交到外层的try,如果外层不处理这个异常,异常将继续往外【抛,如果都不能处理,则会传递到最外层,如果还是没有处理,就终止异常所在的线程。
- 如果try执行时没有发生异常,将执行else语句
- 无论try中是否发生异常,finally子句最终 都会执行。