首页 > 编程语言 >python 异常捕获、断言(assert 、finally) 与日志(loguru.logger)

python 异常捕获、断言(assert 、finally) 与日志(loguru.logger)

时间:2024-03-21 16:05:05浏览次数:31  
标签:try err loguru python 代码 except assert 报错 日志

异常捕获

常见的异常类型

代码执行顺序从上到下依次运行的,如果出错了,后面的代码不会出错。 --所以要对异常做处理。

常见的异常的类型,不需要记;平时写代码的时候 经常会报错,积累常见错误,排查问题。
常见异常的报错的类型:NameError,IndexError,KeyError,ValueError,ZeroDivisionError
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

对于自动化编程人员来说,代码报错了怎么排查?–具备基本能力。

  • 1、点击文件跳转到报错行数–看代码除了什么 + 结合报错信息【异常类型+原因】
  • 2、debug 调试: 单步 【直接单步【不会进入函数里】 + step into【进入函数执行】】
    == 不推荐print
    – 日志记录
# NameError: name 'a' is not defined
# a变量没有运行,异常类型:NameError
# print(a)

#IndexError: list index out of range
# 列表索引超过范围:异常类型 IndexError
a = [1,2,3]
print(a[100])

# KeyError: 'passwd'
# 字典的key错误了,key不存在的,KeyError
# b = {"name":"程程"}
# print(b["passwd"])

#ValueError: invalid literal for int() with base 10: 'b'
# 值错误: int转化不了一个字符串里面是字母的。 ValueError
# a = "b"
# print(int(a))

# ZeroDivisionError: division by zero
# 除数不能为0 : 异常类型: ZeroDivisionError
# print(1/0)

异常捕获

异常捕获:我的代码如果报错了 不会向下继续运行了,后面代码白写了。当代码报错了时候,需要进行处理。
– 先捕获错误

  • 然后再处理后续操作。

问题1: 如何去捕获错误?

  • 第一步: 先找到代码报错的行数是哪一行?
  • 第二步: 加一个代码捕获: try

语法1:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except:
发生了错误,处理代码

这个语句执行完成之后,再执行后续的代码。继续向下运行其他的代码。不会中断代码运行。

问题: 怎么判断代码是否可能会报错呢?这样的代码我才需要加上try语句。

  • 数据不是由程序员控制代码 就会容易出现异常
    • 1) 用户输入数据, 加上异常不会
    • 2)函数参数传参进来,变量用户控制的
    • 3)数据是由其他的函数运行后的结果生成的 拿到了返回值 正常运行,但是返回值没拿到,就会报错了。
    • 4)断言错误,影响到用例是否通过的结果。

语法2:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except Exception as err:
# 捕获了这个异常并且把这个异常信息存在一个变量里。err
发生了错误,处理代码

# 语法1:
# a = [1,2,3]
#
# try:
#     # 可能会报错的代码,先运行try语句里的代码; 如果报错了,会执行except里面的代码;
#     print(a[1])
# except:
#     # 发生了错误,处理代码
#     print("索引错误!")
#
# print("其他的后续代码...")

#  语法2:
a = [1,2,3]
try:
    # 可能会报错的代码,先运行try语句里的代码; 如果报错了,会执行except里面的代码;
    print(a[100])
except Exception as err:  # 捕获了这个异常并且把这个异常信息存在一个变量里。err
    # 发生了错误,处理代码
    print(f"索引错误!:{err}")
print("其他的后续代码...")

异常的进阶用法

语法1:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except:
发生了错误,处理代码

这个语句执行完成之后,再执行后续的代码。继续向下运行其他的代码。不会中断代码运行。

语法2:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except Exception as err: # 万能捕获
# 捕获了这个异常并且把这个异常信息存在一个变量里。err
发生了错误,处理代码

语法3: 捕获不同的类型异常 做不同的操作处理。【错误1-日志; 错误2-发送邮件,错误3-警告】
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
如果try里的错误类型匹配except后的异常类型 才会捕获 不然不会。仍然执行try里面的语句,会终止代码运行。
except 异常类型 as err:
# 捕获了这个异常并且把这个异常信息存在一个变量里。err
发生了错误,处理代码

总结: 针对不同的异常类型去做异常异捕获比较麻烦。我们可以直接用万能捕获。

  • 如果代码量不大 项目不负责可以用万能匹配 但是不推荐。
  • 代码量大了 项目更加要求精细时候,我们区分异常类型 分别做捕获 分别不同的处理。
  • 推荐:先做不同类型捕获 然后再来万能的兜底。

# a = [1,2,3]
# try:
#     # 可能会报错的代码,先运行try语句里的代码; 如果报错了,会执行except里面的代码;
#     print(a[100])
# except IndexError as err:  # 捕获了这个异常并且把这个异常信息存在一个变量里。err
#     # 发生了错误,处理代码
#     print(f"索引错误!:{err}")
# print("其他的后续代码...")

# a = [1,2,3]
# try:
#     # 可能会报错的代码,先运行try语句里的代码; 如果报错了,会执行except里面的代码;
#     print(a[100])
# except KeyError as err:  # 捕获了这个异常并且把这个异常信息存在一个变量里。err
#     # 发生了错误,处理代码
#     print(f"索引错误!:{err}")
# print("其他的后续代码...")


a = [1,2,3]
b = {"name":"程程"}
try:
    # 可能会报错的代码,先运行try语句里的代码; 如果报错了,会执行except里面的代码;
    print(a[1])  #如果这行代码代码出错,从这个位置跳转到except了,后面的语句不会执行。
    key = b["passwd"]  # 这个代码可以运行 但是因为异常类型不对  没有捕获成功。
except IndexError as err:  # 捕获了这个异常并且把这个异常信息存在一个变量里。err
    # 发生了错误,处理代码
    print(f"索引错误!:{err}")
except KeyError as e:
    print(f"key错误{e}")

except Exception as err:  # 万能兜底
    print("代码执行错误!")
print("其他的后续代码...")

手动捕获异常

语法1:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except:
发生了错误,处理代码

这个语句执行完成之后,再执行后续的代码。继续向下运行其他的代码。不会中断代码运行。

语法2:
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
except Exception as err: # 万能捕获
# 捕获了这个异常并且把这个异常信息存在一个变量里。err
发生了错误,处理代码

语法3: 捕获不同的类型异常 做不同的操作处理。【错误1-日志; 错误2-发送邮件,错误3-警告】
try:
执行的可能会报错代码 如果报错了,会执行except里面的代码;
如果没有报错,正常执行try语句,except里不会执行。
如果try里的错误类型匹配except后的异常类型 才会捕获 不然不会。仍然执行try里面的语句,会终止代码运行。
except 异常类型 as err:
# 捕获了这个异常并且把这个异常信息存在一个变量里。err
发生了错误,处理代码

语法4: raise 主动抛出异常
代码本身没有问题,没有错误; 但是程序员主动抛出异常,让代码自动终止运行。
报错了 中断代码运行了,后续的代码不会运行了。

什么场景下会要求主动抛出异常呢? --理解
案例: 测试用例执行时候,针对每一个用例做断言【预期结果 vs 执行结果】 如果不一样,断言失败了;
因为测试用例结果记录到日志里;捕获断言的异常,记录到日志;
但是因为捕获了,这个用例断言不会失败了,报告统计里【pytest】不会认为是失败了。
这种场景下: 先捕获了异常,做日志记录操作; 然后再raise抛出这个异常,让测试用例失败显示在报告里。

# def add(a,b):
#     return a + b
#
# print(add(1,2))
# print(add(-1,-3))
# 需求: 不能输入负数 【用户名:不让输入特殊字符】,遇到负数之后,主动异常了。

def add(a,b):
    if a < 0 or b<0:
        raise ValueError("不能为负数")  # 主动抛出异常,raise关键字
    return a + b

print(add(1,2))
print(add(-1,-3))  # 报错了 中断代码运行了,后续的代码不会运行了。

print("后续的代码执行...")

运行结果如下:

Traceback (most recent call last):
  File "D:\BaiduNetdiskDownload\1-Python基础\20231115_py65基础第八节课-异常捕获和日志处理\day08_异常捕获和日志\d4_手动抛出异常.py", line 54, in <module>
    print(add(-1,-3))  # 报错了 中断代码运行了,后续的代码不会运行了。
  File "D:\BaiduNetdiskDownload\1-Python基础\20231115_py65基础第八节课-异常捕获和日志处理\day08_异常捕获和日志\d4_手动抛出异常.py", line 50, in add
    raise ValueError("不能为负数")  # 主动抛出异常,raise关键字
ValueError: 不能为负数

断言

断言: 预期结果和执行结果比对 判断测试是否通过。

  • 1、if 预期结果 == 执行结果
  • 2、 assert断言

assert语法:
1、assert 执行结果 == 预期结果
2、如果断言失败了 就会报错 AssertionError异常类型。会终止后面的代码运行
3、加提示信息,会显示再结果里。 只有断言失败了 会显示。 断言成功了,提示不会显示。
4、在项目里。因为断言可能会失败 所以一般会在断言前后加上try语句 异常捕获;

  • 抓到报错之后 记录日志
  • 还要主动抛出异常 为了让用例显示失败。

actural = 6
expected = 5
try:
    assert actural == expected,"断言失败了,5=!6"
except AssertionError as err:
    print(f"断言失败{err}")  #记录到日志
    raise err

print("566666")

finally的使用

finally语法: 写在try except语句。

  • 捕获了异常执行
  • 没有捕获也会执行
actural = 6
expected = 5
try:
    assert actural == expected,"断言失败了,5=!6"
except AssertionError as err:
    print(f"断言失败{err}")  #记录到日志
    raise err
finally:
    print("566666")

日志

日志: 平时测试工作有没有看过日志么?

  • 开发项目的里日志,服务器里收集日志 :Linux命令 tail -f
  • app里收集日志 :adb logcat
  • 日志查看原因目的是什么.?
    == 日志是代码记录的信息,写代码的人会把代码过程中步骤或者关键信息记录到日志
    == 方便除了问题 通过日志查找问题。
    == 任何完整框架【开发项目】 都应该有日志系统。== 自动化框架也有日志。

对于写代码的人 都需要设计日志进入代码里。

日志级别:

  • TRACE: 废话 基本不用
  • DEBUG:用于调试程序,很详细信息 变量值的,于主体业务功能没有关系,在线上环境里没有的
  • INFO: 用于记录日常信息,主体业务功能信息 ==最多显示
  • WARNING: 警告信息,触发犯错的边缘
  • ERROR: 犯错了 出错了 异常了 断言失败 == 用的比较多
  • CRITICAL: 严重错误信息,崩溃了 无法继续运行了 致命错误

优先级: critical > error > waring > info > debug

自动化测试的日志功能库:

  • logging:自带库
  • loguru : 第三方的库 == 我们用这个 因为更方便 代码简单。
    • 安装: pip install loguru ,如果安装失败了 因为切换国内源
    • 导入: from loguru import logger

现在的做法日志打印再在控制台的,最终项目的日志肯定要写到文件里。-- 生成日志文件的。

from loguru import logger

# 打印日志 info 级别的日志
logger.info("日常操作日志")

# 断言失败了 记录日志  error日志
actural = 6
expected = 5
try:
    assert actural == expected,"断言失败了,5=!6"
except AssertionError as err:
    logger.error(f"断言失败{err}")  #记录到日志
    raise err

print("566666")

日志文件

现在的做法日志打印再在控制台的,最终项目的日志肯定要写到文件里。-- 生成日志文件的。
add()方法,参数如下:

  • sink:文件名字
    • 追加模式 持续写入到这个文件里
    • 运行再这个目录里会生成对应的文件 : 以后会做了代码分层之后,路径处理 --pathlib
  • encoding: 编码格式,如果要记录除了英文之外的字符 设置UTF8编码
  • level: 设置的级别及其优先级以上的级别 都会被记录到日志文件里。
    • 优先级: critical > error > waring > info > debug
  • rotation:文件分割:很多系统每天生成一个日志文件。 按照一定规则进行分割。
    • 文件大小: 100MB 超过了 新创建一个继续记录日志
    • 时间分割: 23:59: 每天晚上23:59新创建一个继续记录日志
    • 按照天 week 1 week, 10 day
  • retention: 日志文件的数量,如果文件数量超过设置的数量,老日志会删除。
    • 20 : 最多存储20个日志文件。 多了删除老的。

项目的代码加日志和要求: 最好详细到每一个操作。

from loguru import logger

# 写入日志文件 在最上方 =入口文件里写 run.py  最新执行
logger.add(sink="mytest.log",
           encoding="UTF8",
           level="INFO",
           rotation="1kB",
           retention= 20)

# 登录用例 -- 记录日志信息  加logger
username = input("请输入用户名:")
password = input("请输入密码:")
logger.info(f"输入的用户名是:{username},输入密码是:{password}")

logger.info("进行用户登录操作..")
if username == "admin" and password == "123456":
    msg = "登录成功"
    logger.info("登录成功")

else:
    msg = "登录失败"
    logger.error("登录失败!")

运行结果如下:

请输入用户名:andy
请输入密码:12345
2024-03-21 15:53:35.025 | INFO     | __main__:<module>:31 - 输入的用户名是:andy,输入密码是:12345
2024-03-21 15:53:35.029 | INFO     | __main__:<module>:33 - 进行用户登录操作..
2024-03-21 15:53:35.029 | ERROR    | __main__:<module>:40 - 登录失败!

mytest.log的内容如下:

2023-11-15 22:10:29.916 | INFO     | __main__:<module>:33 - 进行用户登录操作..
2023-11-15 22:10:29.919 | ERROR    | __main__:<module>:40 - 登录失败!
2024-03-21 15:53:35.025 | INFO     | __main__:<module>:31 - 输入的用户名是:andy,输入密码是:12345
2024-03-21 15:53:35.029 | INFO     | __main__:<module>:33 - 进行用户登录操作..
2024-03-21 15:53:35.029 | ERROR    | __main__:<module>:40 - 登录失败!

标签:try,err,loguru,python,代码,except,assert,报错,日志
From: https://blog.csdn.net/qq_35283902/article/details/136910850

相关文章

  • python 之 垃圾回收机制(Garbage Collector,简称 GC)
    垃圾回收机制有三种,主要采用引用计数机制为主,标记-清除和分代回收机制为辅的策略。其中,标记-清除机制用来解决计数引用带来的循环引用而无法释放内存的问题,分代回收机制是为提升垃圾回收的效率。1.引用计数:Python中的每个对象都有一个引用计数,每当对象被引用时,其引用......
  • python 函数(解包、互相调用、作用域、函数的封装、内置函数:eval()、zip()、open())
    函数解包"""1、函数的注释:参数和返回值在注释里可以自动添加显示,只需手动加说明。2、函数的解包【拆包】:函数的参数要传递数据有多个值的时候,中间步骤拿到数据保存在元组或者列表或者字典里。-传递参数的时候加一个*或者**解包-一次拿到元组列表字典的......
  • 身份证ocr,python身份证识别ocr接口代码,实名认证接口
    基于文字识别技术产物的身份证识别接口现已成熟,通过手机、电脑或者摄像头终端设备拍照或者上传身份证图片即可实现身份证照片上文字的识别,从而提取到身份证信息。翔云除了提供身份证识别接口外,还完善了实名认证接口方案,搭配翔云身份证实名认证接口可谓是效率翻倍。身份证......
  • 基于Python3的数据结构与算法 - 17 哈希表
    一、哈希表哈希表是一个通过哈希函数来计算数据存储位置的数据结构,通常支持如下操作:insert(key,value):插入键值对(key,value)。get(key):如果存在键值对为key的键值对则返回其value,否则返回空值。delete(key):删除键为key的键值对。1.直接寻址法当关键字的全域U比较小......
  • 通俗易懂解释python和anaconda和pytorch以及pycharm之间的关系
    Python:Python就像是一门编程语言的工具箱,你可以把它看作是一种通用的编程语言,就像是一把多功能的工具刀。你可以使用Python来编写各种类型的程序,就像使用工具刀来制作各种不同的手工艺品一样。Anaconda:Anaconda就像是一个装有不同种类工具的大工具箱。这个工具箱里包括了Py......
  • 学会Python有哪些可以做的兼职?所有途径全在这里了...
    可以干的兼职有好多,主要围绕Python的应用方向来。自媒体现在很多搞技术的都开始进入自媒体领域,比如微信公众号、知乎、B站、抖音、小红书等。这些平台上只要你有流量,你就可以通过广告、播放量、带货等方式赚钱。当然了,自媒体需要积累,如果能够忍受前期0收入0阅读阶段,不断......
  • python statlic lib embedding
    pythonstaticlib因为默认没有编译内置库,因此需要配置setup.local文件,把内置库编译到staticlib。参考:https://wiki.python.org/moin/BuildStatically。(./configure--disable-shared即可)注意是Setup.local,不是Setup.dist*static*#GNUreadline.UnlikepreviousPythoni......
  • Python统计初步
    文章目录基本统计特征区间统计PandaspandasGUIPython科学计算:数组......
  • 2024. 1华为od机试C卷【传递悄悄话】Python
    题目给定一个二叉树,每个节点上站着一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。初始时,根节点所在位置的人有一个悄悄话想要传递给其他人,求二叉树所有节点上的人都接收到悄悄话花费的时间。输入描述0920-1-1157-1-1-1-132注:-1表示空节点输出......
  • Python函数每日一讲11 - isinstance()
    引言在Python编程中,我们经常需要检查一个对象是否属于某个特定的类或类型。为了实现这个目的,Python提供了isinstance()函数。通过本文的介绍,你将了解isinstance()函数的基本语法、用法示例以及在实际工作中的应用场景,帮助你更好地理解和应用这一函数。语句概览isinstance()函数......