异常处理
程序错误分为两种:语法错误 和 异常错误
语法错误:代码没有按照python规定语法去写,发明创造产生的错误 #语法错误抑制不了
异常错误:在代码语法正确的前提下,程序报错就是异常 #异常错误可以抑制
#try…except… 基础语法 用于解决程序异常问题
#raise 可以主动抛异常,异常类可以自定义
异常的分类
IndexError 索引超出序列的范围
KeyError 字典中查找一个不存在的关键字
NameError 尝试访问一个不存在的变量
IndentationError 缩进错误
AttributeError 尝试访问未知的对象属性
StopIteration 迭代器没有更多的值
AssertionError 断言语句(assert)失败
EOFError 用户输入文件末尾标志EOF(Ctrl+d)
FloatingPointError 浮点计算错误
GeneratorExit generator.close()方法被调用的时候
ImportError 导入模块失败的时候
KeyboardInterrupt 用户输入中断键(Ctrl+c)
MemoryError 内存溢出(可通过删除对象释放内存)
NotImplementedError 尚未实现的方法
OSError 操作系统产生的异常(例如打开一个不存在的文件)
OverflowError 数值运算超出最大限制
ReferenceError 弱引用(weak reference)试图访问一个已经被垃圾回收机制回收了的对象
RuntimeError 一般的运行时错误
SyntaxError Python的语法错误
TabError Tab和空格混合使用
SystemError Python编译器系统错误
SystemExit Python编译器进程被关闭
TypeError 不同类型间的无效操作
UnboundLocalError 访问一个未初始化的本地变量(NameError的子类)
UnicodeError Unicode相关的错误(ValueError的子类)
UnicodeEncodeError Unicode编码时的错误(UnicodeError的子类)
UnicodeDecodeError Unicode解码时的错误(UnicodeError的子类)
UnicodeTranslateError Unicode转换时的错误(UnicodeError的子类)
ValueError 传入无效的参数
ZeroDivisionError 除数为零
获取错误行号和文件名(了解)
#(了解)系统底层获取行数和文件名的函数( 只有在程序异常时才能触发 )
def return_errorinfo(n):
import sys
f = sys.exc_info()[2].tb_frame.f_back
if n==1:
return str(f.f_lineno) #返回当前行数
elif n == 2:
return f.f_code.co_filename #返回文件名
1、IndexError 索引超出序列的范围
lst = [1,2,3] lst[1000]
左边是错误类型,右边是错误的描述
2、KeyError 字典中查找一个不存在的关键字
dic = {"a":1,"b":2} dic["c"]
3、NameError 尝试访问一个不存在的变量
print(jingtian112312313123123123123123123123123123s)
4、IndentationError 缩进错误
if 5 == 5: print(2)
5、AttributeError 尝试访问未知的对象属性
class MyClass(): a = 100 obj = MyClass() obj.abc
6、StopIteration 迭代器没有更多的值
it = iter(range(3)) res = next(it) res = next(it) res = next(it) res = next(it)
7、AssertionError 断言语句(assert)失败
assert猜的意思 , 叫断言,
如果断言是正确的没有任何反应,代码正常执行
如果是错误的直接报错,终止程序
使用assert断言是学习python一个非常好的习惯,python assert 断言句语格式及用法很简单。在没完善一个程序之前,我们不知道程序在哪里会出错,
与其让它在运行最崩溃,不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助。本文主要是讲 assert 断言的基础知识
python assert断言的作用
python assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。
assert 5 < 3 print(111)
报错后,后面的代码不再执行
异常处理的语法
try … except … 来抑制错误
把有可能报错的代码放到try这个代码块当中,
如果有报错,直接执行except这个代码块
如果没有报错,不执行except这个代码块
在异常处理当中,所有的异常错误类都默认继承 BaseException Exception 普通异常的父类(了解)
我们写except时,不写异常类型,默认都是BaseException
#类型上的子父关系
from collections import Iterator,Iterable print(issubclass(Iterator, Iterable))
迭代器是可迭代对象的子类
所有异常都继承于BaseException
1.基本语法
class MyClass(): a = 6 try: lst = [1,2,3] lst[1000] except: pass try: lst = [1,2,3] lst[1000] except BaseException: pass
捕获异常,程序就可以按照我们设计的方向运行,当有异常时,执行except的代码块;没异常时,执行try的代码块
写代码时有时只是想让代码可以跳过某些错误,继续运行下去,会直接使用异常捕获,而不标明具体要捕获的错误是什么。此时会出现告警如上图,原因如下
这时pycharm就会提示:“Too broad exception claus”
直译过来就是:“例外的条款太广泛”
原因就是except之后没有标明具体的异常。
在Python里是,try后面使用except而不带任何异常类型,或者所接异常类太宽泛。这种使用方式是支持的,代码也可以正常运行。
只是except会捕获所有的错误,所以无法识别出具体的异常信息。
解决办法,指明具体异常类
2.带有分支的异常处理
try: # lst = [1,2,3] # lst[1000] # dic = {"a":1,"b":2} # dic["c"] # print(lisi) MyClass.abc() except IndexError: print("下标越界1") except KeyError: print("字典的键不存在2") except NameError: print("这个变量不存在的3") except : print("有异常错误4")
当有多个异常分支时,执行try中的代码,遇到异常,根据异常类型,执行相应except中的代码,后续代码不再执行
3.处理生成器的异常报错
def mygen(): yield 1 yield 2 yield 3 return [1,2,3] try: gen = mygen() print(next(gen)) print(next(gen)) print(next(gen)) print(next(gen)) # 给StopIteration这个类创建出来的对象起一个别名叫e """ 当你打印对象时,会触发内部__str__方法,通过一些列的调用,返回出最后的返回值 """ except StopIteration as e: # 可以获取返回值 print(e) """ # 额外的扩展 res = str(e) print(res , type(res) , "<======>") res2 = eval(res) print(res2,type(res2)) """
except StopIteration as e 是给StopIteration类创建个对象,起个别名为e,通过__str__方法,打印对象,就是打印返回值
也可以except异常父类:
BaseException有__str__方法,所以只要异常被捕获后有返回值,打印对象,返回值即被打印
4.异常处理的其他写法
1 .try … except … else …
当try这个代码块当中没有报错的时候,执行 try 和 else 分支
如果try代码块有报错,就不执行else这个分支,执行except分支
try: # lst = [1,2,3] # lst[1000] print(123) except: pass else: print("执行了else分支 ... ")
代码没报错,执行try和else里面的代码
代码有报错,执行try中报错之前的代码,和except中的代码,不执行else中的代码
2.try … finally … 无论代码是否报错,都必须要执行的代码写在finally这个代码块当中
场景:应用在异常环境下, 保存数据或者关闭数据库等操作, 必须要在数据库程序崩溃之前执行的代码写在finally代码块中;
try: lst = [1,2,3] lst[1000] finally: print(234678)
代码中有报错,还是执行了finally中的代码
3.try … except … else … finally …
try: lst = [1,2,3] lst[1000] # print(123) except: print(456) else: print("执行了else分支 ... ") finally: print("执行关闭数据库操作")
代码中有报错,执行try报错之前的代码,except中的代码,finally中的代码
主动抛异常
有时候我们需要根据报错,得到错误的信息
可以在程序的指定位置手动抛出一个异常?答案是肯定的,Python 允许我们在程序中手动设置异常,使用 raise 语句即可。
读者可能会感到疑惑,即我们从来都是想方设法地让程序正常运行,为什么还要手动设置异常呢?
首先要分清楚程序发生异常和程序执行错误,它们完全是两码事,程序由于错误导致的运行异常,是需要程序员想办法解决的;
但还有一些异常,是程序正常运行的结果,比如用 raise 手动引发的异常
BaseException 所有异常类的父类
Exception 普通异常类的父类
raise + 异常错误类 / 异常错误类对象 一旦抛异常,则程序会中断,下面的代码不再执行
(1) raise 基本语法
raise KeyError raise KeyError() #括号中跟描述信息
raise抛出异常,后面必须接异常类型或异常对象,否则报错
主动抛出异常,程序报错。一般抛异常,就将特定的异常类型写清楚
try: raise except: pass try: raise except BaseException: pass
(2) 自定义异常错误类
必须继承异常类的父类 BaseException
# return_errorinfo必须在报错的情况下才能触发内部相应方法获取当前行号和文件名 def return_errorinfo(n): import sys f = sys.exc_info()[2].tb_frame.f_back if n == 1: return str(f.f_lineno) #返回当前行数 elif n == 2: return f.f_code.co_filename #返回文件名 # 通过主动抛出异常,来获取响应的数据 def get_info(n): try: raise except: return return_errorinfo(n) # 自定义异常错误类 class MyException(BaseException): def __init__(self,error_num,error_msg,error_filename,error_linenum): self.error_num = error_num self.error_msg = error_msg self.error_filename = error_filename self.error_linenum = error_linenum eye = "轮回眼" try: if eye == "轮回眼": raise MyException( 404,"人类没有轮回眼",get_info(2) , get_info(1) ) except MyException as e: # 给自定义MyException异常类的对象起个别名叫做e print(e.error_num) print(e.error_msg) print(e.error_filename) print(e.error_linenum)