1 异常处理
墨菲定律:如果一个系统或项目可能出现错误,那么这个错误一定会发生
错误 != 异常
异常时意识到错误即将出现,采取正常流程意外的动作去处理,引发异常;执行这个异常动作,就表明对异常进行捕获
登录出现了异常,没有超过并不是错误。什么是错误?登录不超过造成了功能不能用
1.1 异常理解
异常,是程序出现了意想不到的情况
有异常出现 ===》 解决
如果异常不解决,会导致程序崩溃、停止运行
如50个测试用例,在第3个测试用例出现了异常,后面的测试用例不会运行了
问:异常对程序进行处理如果程序出现异常怎么办
lst = ['xiaoyi']
print(lst[5])#越界
"""
IndexError: list index out of range
"""
1.2 异常捕获
异常捕获: 提前知道有什么问题,去捕获他异常捕获,捕获异常:让程序不会被异常影响
如果出现了异常,会让他按照事先的规则去执行对应的操作:记录错误日志。log
try ..要运行的有可能发生异常的代码:
代码
except 异常:
出现异常的时候要运行的代码(执行的操作),记录日志
一旦try当中出现异常,立即调到except 语句,try剩下的代码不会再执行
例子:
#不会出现异常的代码没有必要写入try中
lst = ['xiaoyi']
try:
#有可能出现异常的代码
#会执行
print(lst[5])
print("try.....")
#一旦try当中的代码报错,立即调到except,
#try报错代码的下面将不会再执行
except:
#如果出现异常,会执行except 分支的代码
print("记录错误日志")
print("running....")
print("ending....")
"""结果
记录错误日志
running....
ending....
"""
lst = ['xiaoyi', 'xiaoer', 'xiaosan','xiaosi','xiaowu', 'xiaoliu']
#不会有错误日志,正常执行
"""结果
xiaoliu
try.....
running....
ending....
"""
问: 怎么保证准确知道哪些代码会出现异常,把try加到哪?会不会真正可能报异常的地方事先没有try漏掉了
ANS:根据lst的不同,lst[5]有时会出现异常,有时不会,根据代码的能力,代码的健壮性问题。
exception 的好处坏处
- 好处:有错误都能捕获
- 坏处:没有针对性
若是每行代码都加try,没有意义
#不停加try
try:
pass
except:
pass
try:
pass
except:
pass
#没有意义
具体错误,具体加try
a = 'a'
b = 'b'
#如果a b 是数字,这就不用加异常,
#事先不知道数据类型,则需要进行异常捕获
try:
print(a * b)
except:
print("参数错误,记录日志")
#若确定了a, b 都是数据,需要加try? x需要,分子不能为0
a = 4
b =1
try:
print(a / b)
except:
print("参数错误,记录日志")
#最基础的异常捕获
#好的程序员:会知道哪一行代码是需要加异常处理的
#会知道什么代码需要放到try
#异常是好的还是坏的?
#出现异常是好事还是坏事?提前发现异常是好事;若在调试发现异常,是好事,有机会修改
lst = ['xiaoyi']
try:
print(lst[0])
except:
print("参数错误,记录日志")
1.3 捕获的异常赋值给变量
格式:
try:
pass
except Exception as err:
pass
例子:
lst = ['xiaoyi']
a = 4
b =0
try:
print(a / b)
print(lst[3])
#如 with open() as f:
#将捕获的异常赋值给err变量,知道报什么错误
except Exception as err:
print("程序出现错误{}".format(err))
"""结果:
程序出现错误division by zero
"""
1.4 异常处理的进阶版
将这行代码有可能出现的报错情况均列出来
格式:
try:
pass
#可以提前运行知道错误类型
except IndexError as e: #提前告知什么错误欸写
pass
except ZeroDivisionError as e:
pass
#不管有没有报错,finally都会执行
finally:
pass
例子:
"""
进阶版异常捕获
指明出现的异常类型
先不要加异常,让他报错(开发主动试错)
对每一种不同类型的异常
分开处理,进行不同的处理
"""
lst = ['xiaoyi']
try:
print(4 / 0)
lst[3] # IndexError
#可以提前运行知道错误类型
except IndexError as e: #提前告知什么错误欸写
print("出现异常:{}".format((e)))
except ZeroDivisionError as e:
print("出现除法错误:{}".format(e))
finally:
print("hello world")
若2个语句都存在异常,需要分开写try
#无法同时捕获2个异常,第一个异常捕获到就停止了
#如果需要2个都提示
#想捕获多个异常,每行可能出现异常的代码都要加try
lst = ['xiaoyi']
a = 4
b =0
try:
print(a / b)
except Exception as err:
print("程序出现错误{}".format(err))
try:
print(lst[3])
except Exception as err:
print("程序出现错误{}".format(err))
"""结果
程序出现错误division by zero
程序出现错误list index out of range
"""
1.5 手动抛出异常raise
让程序报错,即使没有错误发生也可以让程序报错
def girl_team(age, gender):
if age > 22:
raise ValueError("age must be 小于22")
print("可以加入女子队")
girl_team(23, '女')
"""结果
raise ValueError("age must be 小于22")
ValueError: age must be 小于22
"""
1.6 错误类型
有时不知道什么错误类型,则记住下列常见异常
常见的异常
- importError : 无法引入模块或包
- indexError:下标索引超出序列边界
a = '1234'
print(a[1000])
- nameError:使用一个还未赋予对象的变量
- syntaxError:代码逻辑语法出错,不能执行,不能捕获
#语法错误不能被捕获
try:
wwwww'dd'
except:
print("hellp ")
"""结果
wwwww'dd'
^
SyntaxError: invalid syntax
"""
- typeError:传入的对象类型与要求不符
- valueError:传入一个不被期望的值,即使类型正确
print(int('a'))
- keyError:试图访问你字典不存在的键
d = {"a" : 1, "b": 2}
print(d{"c"})
- ioError:输入输出异常。文件操作
- attributeError
a = 123
a.append()
1.7 异常分组
可不可以把异常分组?
"""
分组的好处:
如果发现一个验证级别的代码,为阻塞级别的bug, 通知所有相关人员查找
轻微级别的bug
针对不同的组进行不同的操作
同时只会有一个错误发现,
"""
try:
1/0
['uuu'][0]
{"name":"xiaoyi"}['age']
except (IndexError,KeyError) as e:
#如果是阻塞bug,短信通知
print("可以同时捕获 IndexError 和 KeyError")
#拆分不是划分为阻塞错误,错误等级分组归类,做对应的处理
except KeyError as e:
print("eoof")
except ZeroDivisionError as e:
#轻微bug,记录日志
print("除法不能为0")
# #能不用就不用,图方便用的,对代码不负责
# except Exception as e:
# print("其他错误类型")
except:和if一样只能捕获一次异常,若异常同时存在2个错误,只会捕获一个
"""
如果2个except捕获同一个错误,执行不一样的处理会怎么样?
excep 只会执行一次如下例子,只会执行一个 2==2
"""
if 2 == 2:
pass
elif 2 == 2:
pass
elif 2 == 2:
pass