1、Python中常见的异常 & 捕获异常
1、常见异常
1、NameError: name 'a' is not defined
2、IndexError: list index out of range
3、KeyError: 'nam'
4、ValueError: invalid literal for int() with base 10: 'b'
5、ZeroDivisionError: division by zero
2、如何分析、解决这些异常
1、分析异常
1、查看控制台的报错信息,报错信息会显示行号、点击文件可以跳到问题行
2、通过debug调试去排查,步骤:断点、单步调试,函数内部调试运行、计算器运算结果,步骤如下:
step over、step out、step into,具体可以参考:Step into, Step over, Step out区别_step into和step over_叼辣条闯天涯的博客-CSDN博客
一般哪里会出现异常呢?
一般是开发者控制不了的地方,例如:用户输入数据、用户传参、函数返回值调用,需要加上异常捕获
2、捕获异常
1、使用 try......except语句,被动抛出异常,语句公式如下:
try:
可能出现异常的代码 -- 一定会执行的,不一定会报错 (用户控制数据 + 断言)
except:
异常发生的时候会执行的代码,没有异常不会执行
except 异常具体类型 as e:
异常发生的时候会执行的代码,没有异常不会执行
except Exception as e:-- 兜底捕获
异常发生的时候会执行的代码,没有异常不会执行
finally:
异常是否捕获了都会执行的代码 -- 意义不大 不需要重点掌握 能看懂就行
============简单点就是如下:===============
try:
报错代码
except:
处理手段和结果,包括但不限于:日志记录、警告、提示等
finally:
一定会执行,不论try中的代码会不会报错
================手动抛异常==================
raise: 主动抛出异常
语法逻辑:机制不会因为报错影响后面的代码运行
1、先运行 try中的代码,如果报错,会执行except中的代码,再执行后续代码
2、try中的代码不报错,不会执行except中的语句,直接运行后续代码
举例:
没有使用异常捕获之前:
使用异常捕获之后:
2、使用raise关键字,主动抛出异常 ,语法公式如下:
可能有问题的代码
raise ValueError("错误提示") # ValueError只是错误的一种,具体的错误类型,根据实际情况而定
if a < 0 and b < 0:
raise ValueError("输入值小于0,不符合条件")
什么时候用raise?
开发者根据业务逻辑,提前规避一些异常时,可以主动抛出异常,让代码运行终止,其目的是,更早的发现问题,主动排除错误,举个简单的例子:
扩展:自动化场景中,什么时候需要主动抛出异常?
- 执行用例,判断执行结果和预期结果是否一致,这里使用断言,断言失败的话,捕获异常,记录日志
- 一旦捕获了异常,用例不算做失败用例,影响测试报告,因此需要主动抛出异常
3、捕获异常的进阶方法
在except后加上 except Exception as err,会将错误信息保存在err变量中,可以获取本身的报错信息,举个例子:
没有捕获异常前的报错:
使用了 Exception 之后的报错:
真实项目情况下,需要对不同的报错信息进行不同的处理:记录日志,警告,发送邮件等。
- 尽量去区分异常进行捕获,优先使用
- 最后加上Exception 兜底
例如:
命中写出来的异常时:
命中兜底逻辑时:
3、断言
定义:断言是 assert,主要用在实际结果与预期结果的对比中
类型:
- if :使用if条件判断做断言,用的表较少
- assert:使用较多
断言的结果:
- 成功:如果断言成功,不会有成功的提示
- 失败:如果断言失败,抛出异常,代码终止,会在测试报告中显示用例失败
- 扩展:AssertionError默认没有提示信息详细展示,需要手动添加备注
注意:
断言失败,那么需要做异常的捕获,需要写入日志,另外断言失败后,如果有用到代码用到的数据,那后续的代码也没必要执行了~
写一个简单的断言:
str1 = "123hcbhd"
str2 = "cdhvcgdcvkjdf"
try:
assert len(str1) == len(str2),f"2个字符串的长度不相等"
except AssertionError as e:
logger.error(e)
raise e
结果:
2023-09-15 18:44:48.979 | INFO | __main__:<module>:4 - 记录日志
2023-09-15 18:44:48.979 | ERROR | __main__:<module>:19 - 断言失败了判断错误 a != b
2023-09-15 18:44:48.980 | ERROR | __main__:<module>:38 - 2个字符串的长度不相等
Traceback (most recent call last):
File "E:\python310\py57\day08_导包与模块以及异常处理\日志模块\日志.py", line 39, in <module>
raise e
File "E:\python310\py57\day08_导包与模块以及异常处理\日志模块\日志.py", line 36, in <module>
assert len(str1) == len(str2),f"2个字符串的长度不相等"
AssertionError: 2个字符串的长度不相等
图示明显点:
4、日志处理,使用 loguru包
定义:用来实时打印日志的,用法如下:
1、先下载 loguru 库,可以通过setting或者pip install loguru两种方式来下载
备注我下载loguru时遇到的问题:一直没下载成功,并且遇到了python版本与pip版本不一致的情况,这时候,可以卸载python,再重新安装,安装时换了目录安装,亲测有效
2、使用loguru来打印日志,可以查看下面的图片:
1、进阶日志用法
可以通过如下关键字,增加日志的辨识度与有效度:
- sink = 文件名,直接写在当前的目录生成文件,代码分层后,放到输出目录logs中,需要做路径处理(追加模式,可持续写入文件内容、文件名方便识别即可)
- encoding:编码,日志中肯定有中文,防止识别不出
- level = “INFO”:必须大写,设置完级别后,这个级别及其以上级别的日志都会显示在文件中
- rotation:进行文件分割,通过时间,大小控制,例如: - rotation=“20MB”,-rotation=“1 day”
- retention:日志文件的个数,超过就会将旧文件删除
备注:日志的级别
日志级别:
- TRACE: 废话 基本不用
- DEBUG:用于调试程序,很详细信息 变量值的,于主体业务功能没有关系,在线上环境里没有的
- INFO: 用于记录日常信息,主体业务功能信息
- WARNING: 警告信息,触发犯错的边缘
- ERROR: 犯错了 出错了 异常了 断言失败
- CRITICAL: 严重错误信息,崩溃了 无法继续运行了 致命错误
优先级: critical > error > waring > info > debug
实战演练:
from loguru import logger
logger.add(
sink = "my_log",
encoding="utf8",
level="INFO",
rotation="1MB",
retention=10,
)
# 登录案例demo
username = input("请输入用户名:")
password = input("请输入密码:")
# logger.info(f"用户名是:{username},密码是{password}")
if username == "admin" and password == "123456":
logger.info("进行登录操作···")
msg = "登录成功"
logger.info("登录成功!")
else:
logger.info("正在进行登录操作")
msg = "登录失败"
logger.info("登录失败!")
结果看截图:
一看就会,一写就废,练习起来吧~