异常 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/0print('end')except:print('catch the exception')bar()# 执行到1/0异常时,由于使用了try...except捕获到异常,则异常生成位置之后语句将不再执行,转而执行对应的except部分语句begincatch the exception
捕获指定类型的异常
try:print('begin')c = 1/0print('end')except ArithmeticError: # 数值计算类型异常,可以正常捕获print('catch the exception')try:print('begin')c = 1/0print('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子句最终都会执行。
