python异常处理
异常 Exception
-
错误 Error
逻辑设计错误、笔误、语法错误,即在运行前可以避免的
-
异常Exception
程序执行时的意外情况,前提是没有上面的错误情况,但在某些情况下出现的意外导致程序无法正常执行。
例如open函数操作一个文件,但文件不存在,或网络访问一个文件,突然断网了,就是异常。
异常可以捕获,但错误是不能捕获的
产生异常
- Pyhon解释器检测到异常并引发
def foo():
print('before')
def bar():
print(1/0) # 除0异常
bar()
print('after')
foo() # 运行时会直接抛出
- raise语句显示抛出异常
def bar():
print('before')
raise Exception('my exception') # 显示抛出异常
print('after') # raise后的语句不在执行
bar()
程序会在异常抛出的地方中断执行,如果不捕获,就会提前结束程序
raise语句如果后面什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛出类型异常,一般很少用。
raise后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化。
异常的捕获
# 语法
try:
待捕获异常的代码块
except [异常类型]:
异常处理的代码块
示例:
def bar():
try:
print('begin')
c = 1/0
print('end')
except:
print('catch the exception')
bar()
# 执行到1/0异常时,由于使用了try...except捕获到异常,则异常生成位置之后语句将不再执行,转而执行对应的except部分语句
begin
catch the exception
捕获指定类型的异常
try:
print('begin')
c = 1/0
print('end')
except ArithmeticError: # 数值计算类型异常,可以正常捕获
print('catch the exception')
try:
print('begin')
c = 1/0
print('end')
except KeyboardInterrupt: # 用户中断执行(通常是输入^C),1/0异常不属于这种类型,则不会被捕获
print('catch the exception')
异常类的继承层次
BaseException #所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt # 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规错误的基类
+-- StopIteration # 迭代器没有更多的值
+-- StopAsyncIteration # 由异步迭代的`__anext__()`抛出的异常
+-- ArithmeticError # 所有数值计算错误的基类
| +-- FloatingPointError # 浮点计算错误
| +-- OverflowError # 数值运算超出最大限制
| +-- ZeroDivisionError # 除0异常
+-- AssertionError # 断言语句失败
+-- AttributeError # 对象没有这个属性
+-- BufferError # 缓存错误
+-- EOFError # 没有内建输入,到达EOF 标记
+-- ImportError # 导入模块/对象失败
| +-- ModuleNotFoundError # 模块不存在
+-- LookupError # 无效数据查询的基类
| +-- IndexError # 序列中没有此索引(index)
| +-- KeyError # 映射中没有这个键
+-- MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+-- NameError # 未声明/初始化对象 (没有属性)
| +-- UnboundLocalError # 访问未初始化的本地变量
+-- OSError # 操作系统错误
| +-- BlockingIOError # 调用阻塞异常错误
| +-- ChildProcessError # 子进程异常
| +-- ConnectionError # 连接异常基类
| | +-- BrokenPipeError # 管道读写异常
| | +-- ConnectionAbortedError # 连接失败
| | +-- ConnectionRefusedError # 连接拒绝
| | +-- ConnectionResetError # 连接重置
| +-- FileExistsError # 文件已经存在异常
| +-- FileNotFoundError # 文件未找到异常
| +-- InterruptedError # 中断异常
| +-- IsADirectoryError # 文件操作用在目录上
| +-- NotADirectoryError # 不是目录异常
| +-- PermissionError # 权限异常
| +-- ProcessLookupError # 进程不存在异常
| +-- TimeoutError # 超时异常
+-- ReferenceError # 试图访问已经垃圾回收了的对象
+-- RuntimeError # 一般的运行时错误
| +-- NotImplementedError # 尚未实现的方法
| +-- RecursionError # 超出最大递归深度
+-- SyntaxError # Python 语法错误
| +-- IndentationError # 缩进错误
| +-- TabError # Tab 和空格混用
+-- SystemError # 一般的解释器系统错误
+-- TypeError # 对类型无效的操作
+-- ValueError # 传入无效的参数
| +-- UnicodeError # Unicode 相关的错误基类
| +-- UnicodeDecodeError # Unicode 解码时的错误
| +-- UnicodeEncodeError # Unicode 编码时错误
| +-- UnicodeTranslateError # Unicode 转换时错误
+-- Warning # 警告的基类
+-- DeprecationWarning # 关于被弃用的特征的警告
+-- PendingDeprecationWarning # 关于特性将会被废弃的警告
+-- RuntimeWarning # 可疑的运行时行为(runtime behavior)的警告
+-- SyntaxWarning # 可疑的语法的警告
+-- UserWarning # 用户代码生成的警告
+-- FutureWarning # 关于构造将来语义会有改变的警告
+-- ImportWarning # 导入警告
+-- UnicodeWarning # unicode相关警告
+-- BytesWarning # 字节相关警告
+-- ResourceWarning # 资源使用情况警告
示例:
import sys
try:
sys.exit(1)
except SystemExit: # 使用SystemExit捕获异常
print('catch the exception')
print('outer')
多异常捕获
except可以捕获多个异常
try:
a = 1/0
except ZeroDivisionError:
print('1/0')
except Exception:
print('Exception')
捕获规则:
捕获是从上到下依次比较,如果匹配,则执行匹配的except语句块
如果被一个except捕获,其他的except语句就不会再次捕获了
如果任何一个except都没有捕获到这个异常,则该异常直接抛出
捕获原则:
从小到大,从具体到宽泛
as子句
被抛出的异常,是异常的示例,可以使用as子句获得这个对象
try:
a = 1/0
except ZeroDivisionError as e: # 使用e获得对象
print(e)
except Exception as e :
print(e)
finally子句
在try...except语句块中,不管是否发生了异常,都会执行finally子句
f = None
try:
f = open('text.txt')
except FileNotFoundError as e:
print('{} {} {}'.format(e.__class__, e.errno, e.strerror))
finally: # 无论如何都会执行f的关闭操作
print('clear work')
if f:
f.close()
也可以在finally中再次捕捉异常
f = None
try:
f = open('text.txt')
except FileNotFoundError as e:
print('{} {} {}'.format(e.__class__, e.errno, e.strerror))
finally:
print('clear work')
try:
f.close()
except Exception as e:
print(e)
异常的传递
异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出,如果内层捕获并处理了异常,外部就不能捕获到了,如果最外层还是没有处理,就会中断异常所在的线程
try:
try:
ret = 1/0
except KeyError as e: # 未能捕获异常
print(e)
finally:
print('inner finally')
except:
print('outer catch')
finally:
print('outer finally')
inner finally
outer catch
outer finally
else子句
没有任何异常发生,则执行else子句
try:
ret = 1 * 0
except ArithmeticError as e:
print(e)
else:
print('ok')
finally:
print('finally')
总结
try:
<语句> # 运行代码
except <异常类>:
<语句> # 捕获某种类型异常
except <异常类> as <变量名>:
<语句> # 捕获某种类型的异常并获得对象
else: # 如果没有异常发生执行
<语句>
finally: # 退出try总会执行
<语句>
try工作原理
- 如果try语句中执行时发生异常,搜索except子句,并执行第一个匹配该异常的except子句。
- 如果try中语句执行时发生异常,但没有匹配的except子句,则异常会递交给外层try,如果外层也没有处理这个异常,则继续向外传递,如果都不处理,就终止异常所在的线程。
- 如果在try执行时没有发生异常,将执行else子句中的语句。
- 无论try中是否发生异常,finally子句最终都会执行。

浙公网安备 33010602011771号