异常处理
异常 Exception
错误 Error
逻辑错误,算法写错,
笔误: 变量名写错,
函数或类使用错误
错误可以避免
**异常Exception **
例如:open 函数,文件不存在,或者创建文件时,文件已经存在,或者访问一个网络文件,突然断网,是个意外情况
异常是不可避免的
错误和异常
在高级语言中,一般都有错误和异常,异常可以捕获,并被处理,但是错误是不能被捕获的
产生异常
- raise 语句显式的抛出异常
- Python解释器自己检测到异常并引发它
def bar():
print('~~')
raise Exception('my Exception') # 主动引出异常
print('~~~~')
bar()
异常的捕获
try:
待捕获异常的代码块
except:
异常的处理代码块
举例:
print('before')
try :
print(1/0)
except:
print('error')
print('after')
>>>
before
error
after
###也可以指定异常的类型
print('before')
try :
print(1/0)
except ArithmeticError:# 捕获算术异常
except KeyError: #捕获keyerror异常
print('error')
print('after')
总结: 异常捕获时,except 后面加的错误类型要与上面产生的异常相匹配.不然起不到捕获异常的作用.
上例执行到c=1/0
时产生异常抛出,由于使用了try --except 语句块捕捉到了这个异常,异常生成位置之后语句不在执行,转而执行对应的except部分的语句,最后执行try–except语句块之外的语句
异常类及继承层次
BaseException #基类
+-- SystemExit #解析器请求退出
+-- KeyboardInterrupt #用户中断执行
+-- GeneratorExit #生成器发生异常
+-- Exception #常规错误的基类
+-- StopIteration #迭代器值超出
+-- StandardError #所以的内建标准异常的基类
| +-- BufferError #缓冲错误
| +-- ArithmeticError#算术错误
| | +-- FloatingPointError #浮点数计算错误
| | +-- OverflowError# 数值运算超出最大限制
| | +-- ZeroDivisionError#除(或取模)错误
| +-- AssertionError#断言语句失败
| +-- AttributeError#对象没有这个属性
| +-- EnvironmentError#操作系统错误基类
| | +-- IOError#输入输出操作失败
| | +-- OSError#操作系统错误
| | +-- WindowsError (Windows)#系统调用失败
| | +-- VMSError (VMS)#虚拟机调用失败
| +-- EOFError#没有内建输入,到大EOF标记(end of file)
| +-- ImportError#导入模块错误
| +-- LookupError#无效数据查询的基类
| | +-- IndexError#索引错误
| | +-- KeyError#关键字key错误
| +-- MemoryError #内存溢出错误
| +-- NameError#未声明/初始化对象(属性)
| | +-- UnboundLocalError#访问未初始化的本地变量
| +-- ReferenceError#弱引用
| +-- RuntimeError#一般的运行时错误
| | +-- NotImplementedError#尚未实现的方法
| +-- SyntaxError#Python语法错误
| | +-- IndentationError#缩进错误
| | +-- TabError#Tab和空格错误
| +-- SystemError#一般的解释器系统错误
| +-- TypeError#对类型无效的错误
| +-- ValueError#传入无效的参数
| +-- UnicodeError#Unicode相关错误
| +-- UnicodeDecodeError#编码错误
| +-- UnicodeEncodeError#解码错误
| +-- UnicodeTranslateError#转化错误
+-- Warning# 警告的基类
+-- DeprecationWarning#关于被弃用的特征的警告
+-- PendingDeprecationWarning#关于特征将会被废弃的警告
+-- RuntimeWarning#可疑的运行行为
+-- SyntaxWarning#可疑语法警告
+-- UserWarning# 用户代码生成的警告
+-- FutureWarning#关于构造将来语义会有改变的警告
+-- ImportWarning#导入错误
+-- UnicodeWarning#编码错误
+-- BytesWarning#bytes警告
举例详解:
# 捕获这个异常
import sys
try:
sys.exit(100) #状态返回码 是自己设定状态码
except SystemExit: # 换成Exception能否捕获 (# 不能,)
print('SysExit')
print('outer') # 是否执行?
>>>
SysExit
outer
Exception 及子类
Exception是所有内建的、非系统退出的异常的基类,自定义异常类应该继承自它
SyntaxError 语法错误
Python将这种错误也归到异常类下面的Exception下的子类,但是这种错误是不可捕获的
自定义异常类
从Expection 继承的类
class MyException(Exception): # 自定义的异常类从Exception 继承
pass
try:
raise MyException() # 实例化
except MyException: # 捕获自定义异常
print('catch the exception')
多种捕获
except可疑捕获多个异常
class MyException (Exception):
pass
def foo():
try :
a =1/0
raise NotImplementedError
raise MyException()
except ArithmeticError:
print('Arhth')
except Exception: #多种异常,只要捕获一种则不再继续执行
print('oa')
except : # 相当于except all
print('all')
print('leave here')
# 越具体的异常越往上写,
# 捕获是从到下依次比较,如果匹配,则执行匹配的except语句块/
捕获原则:
- 捕获是从下往下比较,如果匹配,则执行匹配的except语句块
- 如果被一个except 语句捕获,其他except语句就不会再次捕获了
- 如果没有任何一个except 语句捕获到这个异常,则该异常向外抛出
捕获的原则
从小到大,从具体到宽泛
as子句
首先看个例子:
class A :pass
try :
# 1/0
# raise 1
# raise 'abc'
# raise {}
# raise A
# raise A()
except :
print('catch the except')
#上面的都能打印出catch the except
被抛出的异常,应该是异常类的实例,如何获得这个对象呢?使用as子句
class MyException(Exception):
def __init__(self, code, message):
self.code = code
self.message = message
try:
raise MyException
except MyException as e:
print('catch my exception')
except Exception as e :
print('{}'.format(e))
# 运行结果如下, 为什么?
>>> __init__() missing 2 required positional arguments: 'code' and 'message'
raise 后面跟类型是无参构造实例,因此需要两个参数,但并未给,所以会报错
raise语句
raise后要求应该是BaseException类的子类或实例,如果是类,将被无参实例化。
raise后什么都没有,表示抛出最近一个被激活的异常,如果没有被激活的异常,则抛类型异常。这种方式很少用
finally 子句
finally
最终,即最后一定要执行的,try…finally语句块中,不管是否发生了异常,都要执行finally的部分
try:
f = open('test.txt') # 尝试打开
except Exception as e: #文件不存在报错
print('{}'.format(e)) # 打印错误类型
finally: #最终要执行
print('清理工作')
try:
f.close()
except Exception as e:
print(e)
异常的传递
def fo1():
return 1/0
def fo2():
print('fo2 start')
fo1()
print('fo2 stop')
fo2()
foo2调用了foo1,foo1产生的异常,传递到了foo2中。
异常总是向外层抛出,如果外层没有处理这个异常,就会继续向外抛出
如果内层捕获并处理了异常,外部就不能捕获到了
如果到了最外层还是没有被处理,就会中断异常所在的线程的执行。注意整个程序结束的状态返回值。
异常的捕获时机
1,立即捕获 需要立即返回一个明确的结果
2,边界捕获
封装产生了边界
例如:写了一个模块,用户调用这个模块的时间捕获异常,模块内部不需要捕获,处理异常,一旦内部处理了外部调用者就无法感知异常.
例如open函数,出现异常时交给调用者,文件存在,就不用再创建,看是否修改还是删除,
例如自己写了一个类,使用open函数,出现异常不知道如何处理继续向外层抛出,一般来书最外层也是边界,必须处理这个异常,否则线程会退出
else子句
try:
ret = 1 * 0
except ArithmeticError as e:
print(e)
else:
print('OK')
finally:
print('fin')
else子句.没有任何异常发生时则执行
总结
try:
<语句>#运行别的代码
except <异常类> as <变量名>:
<语句> #捕获某种类型的异常并获得对象
else:
<语句>#如果没有异常发生
finally:
<语句> #退出try时总会执行