梦想成为龙骑士的sailan 求补充
一、异常处理概念
1. 什么是异常*
异常是错误发生的信号,程序出错就会产生异常
2. 为什么要处理异常*
为了保证程序的稳定性与容错性,也就是在遇到错误时程序不会崩溃。
3. 异常的三个组成*
1.发生异常的地方\位置
2.异常的种类
3.异常信息\原因
4. 语法错误应什么时候处理*
语法错误是过不了Python解释器的审核的,必须在程序执行前修正好,否者执行不了。
5. 逻辑错误正确解决方法*
分两种可预知,和不可预知;
可预知可应用if判断等方法规避;
不可预知可用try..except...在程序发生错误后进行处理
6. 异常处理的完整语法*
try:
代码块
except 异常类型 as f: # f接受异常信息 PS:as 句柄 可省略
print(f) # 打印异常信息
finally:
代码块
无论上层是否抛异常都会执行,
一般用来进行清理操作,
如关闭文件,关闭数据库等等
7. 常用的异常种类
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
二、异常处理多种使用场景及语法的使用方式
1. 多分支处理异常
使用场景:
当被检测的代码块中有可能触发不同类型的异常时,
针对不同类型的异常,如果我们想分别用不同的逻辑处理,需要使用到多分支的except;
try:
被检测的代码块
except NameError:
触发NameError时对应的处理逻辑
except IndexError:
触发IndexError时对应的处理逻辑
except KeyError:
触发KeyError时对应的处理逻辑
释:类似于多分支的elif,从上到下依次匹配,匹配成功一次便不再匹配其他
2. 多种异常统一用一种逻辑进行处理
可以将多个异常放到一个元组内,用一个except匹配
try:
被检测的代码块
except (NameError,IndexError,TypeError):
触发NameError或IndexError或TypeError时对应的处理逻辑
3. 万能异常Exception
使用场景:
想捕获所有异常并用一种逻辑处理;
try:
被检测的代码块
except NameError:
触发NameError时对应的处理逻辑
except IndexError:
触发IndexError时对应的处理逻辑
except Exception:
其他类型的异常统一用此处的逻辑处理
4. 多分支except跟else的使用
else必须跟在except之后,不能单独存在,
只有在被检测的代码块没有触发任何异常的情况下才会执行else的子代码块
try:
被检测的代码块
except 异常类型1:
pass
except 异常类型2:
pass
......
else:
没有异常发生时执行的代码块
5. finally与try…except…连用解析
语法上讲finally必须放到else之后。
可以使用try...except...finally的形式,
try:
被检测的代码块
except 异常类型1:
pass
except 异常类型2:
pass
......
else:
没有异常发生时执行的代码块
finally:
无论有无异常发生都会执行的代码块
也可以直接使用try...finally的形式,如下
try:
代码块
finally:
代码块
无论被检测的代码块是否触发异常,都会执行finally的子代码块,
因此通常在finally的子代码块做一些回收资源的操作,
比如关闭打开的文件、关闭数据库连接等
三、异常处理中raise的使用*
用于主动触发异常,还可自定义异常
使用场景:
在不符合Python解释器的语法或逻辑规则时,
是由Python解释器主动触发的各种类型的异常,而对于违反程序员自定制的各类规则,
则需要由程序员自己来明确地触发异常,这就用到了raise语句,
raise后必须是一个异常的类或者是异常的实例;
1. 主动触发异常*
class Student:
def __init__(self,name,age):
if not isinstance(name,str):
raise TypeError('name must be str')
if not isinstance(age,int):
raise TypeError('age must be int')
self.name=name
self.age=age
stu1=Student(4573,18) # TypeError: name must be str
stu2=Student('sailan','18') # TypeError: age must be int
2. 自定义异常及输出格式*
class Interface(BaseException):
def __init__(self, msg, x, y, z):
self.msg = msg
self.x = x
self.y = y
self.z = z
def __str__(self):
return "<%s:%s:%s:%s>" % (self.msg,self.x,self.y,self.z)
raise Interface("接口异常", 11, 22, 33) # 调用类,进行定义异常内容
# 触发异常,打印异常信息,会导致上面__str__方法的执行,从而达到自定义异常信息的效果
异常信息
raise Interface("接口异常", 11, 22, 33)
__main__.Interface: <接口异常:11:22:33>
3. 断言assert
使用场景:
多用于测试,用来判断了解程序运行状态等等,断言成功正常执行后续代码,出错则抛出AssertionError,断言的使用应不影响程序代码格局;
salaries=[1.1,2.2]
# if len(salaries) != 3: # 断言效果可以用多种方式实现,使用assert关键字更方便
# raise NameError
assert len(salaries) == 3 # 成功则正常运行后续代码 和上面注释的方法效果一样
print(salaries[2])
四、何时使用异常处理
try...except是我们附加给程序的一种异常处理的逻辑,与主要的工作逻辑是没关系的,
这种东西加的多了,会导致代码可读性变差,异常处理不应滥用,
我们应尽量写好代码逻辑,只有在错误发生的条件无法预知的情况下,
才应该加上try...except。