当前位置: 首页 > news >正文

【Python学习】基础学习(三):异常处理、调试和测试

Python学习全部目录:
【Python学习】基础学习(一):变量与运算、数据类型、函数、类、模块
【Python学习】基础学习(二):文件管理与I/O编程

【Python学习】基础学习(三):异常处理、调试和测试

    • 异常处理、调试和测试
      • 控制异常try-except
      • 调试器pdb
      • Unittest单元测试
      • 异常/警告名称列表

异常处理、调试和测试

控制异常try-except

即使自己的的代码没有错误,但是有时也难以避免潜在的错误,比如说物理环境出错,CPU资源不够,调用的服务失败。
在写代码的时候,考虑如何对捕捉潜在的错误,预先写好对于可能错误的处理。

  1. try-except
    比如处理文件时候,如果读写不存在的文件就会报错:
withopen('no_file.txt','r')asf:print(f.read())# FileNotFoundError: [Errno 2] No such file or directory: 'no_file.txt'

我们需要注意的就是表示异常类型的报错关键词FileNotFoundError,需要手动捕捉这个错误并且进行处理

try:withopen('no_file.txt','r')asf:print(f.read())exceptFileNotFoundErrorase:print(e)withopen('no_file.txt','w')asf:f.write('This is a file for test.')print('new file "no_file.txt" has been written.')

有时候程序执行某种功能会报多种不同的异常,如果异常的处理方案相同,可以在except中写多个异常种类,会按照正常的执行顺序, 一次检测异常,报出第一个遇到的异常:

dic={'name':'Bob','age':20}l=[1,2,3]try:male=dic['gender']l[3]=4except(KeyErrororIndexError)ase:print('ker or index error for: ',e)# ker or index error for: 'gender'
  1. try-except-except
    如果想让多种异常分开处理,就需要写两个except
try:v=dic['gender']l[3]=4exceptKeyErrorase:print('key error for:',e)dic['gender']='Female'exceptIndexErrorase:print('index error for:',e)l.append(4)print(dic)print(l)# key error for: 'gender'# {'name': 'Bob', 'age': 20, 'gender': 'Female'}# [1, 2, 3]
  1. try-except-else
    这个模式在except处理报错情况:
lis=[1,2,3]try:print(lis[3])exceptIndexErrorase:print(e)lis.append(4)print(lis[3])else:print('now is in else.')# list index out of range# 4

else处理没有报错的情况:

lis=[1,2,3,4]try:print(lis[3])exceptIndexErrorase:print(e)lis.append(4)print(lis[3])else:print('now is in else.')# 4# now is in else.
  1. try-except-finally
    不管有没有错误,都会执行到finally内容
    有报错:
lis=[1,2,3]try:print(lis[3])exceptIndexErrorase:print(e)lis.append(4)print(lis[3])finally:print('reach finally.')# list index out of range# 4# reach finally.

没有报错:

lis=[1,2,3,4]try:print(lis[3])exceptIndexErrorase:print(e)lis.append(4)print(lis[3])finally:print('reach finally.')# 4# reach finally.

主要用在不管有没有报错,都想让程序继续执行,不处理任何异常:

try:dd=ddddfinally:print('I know there is an error, just ignore it.')# I know there is an error, just ignore it.# NameError: name 'dddd' is not defined
  1. 记录错误
    使用python内置的logging模块,就可以记录并打印输出错误信息,同时可以让程序继续执行,而不是出错就退出执行:
importlogging lis=[1,2,3]deflogerror():try:print(lis[3])exceptExceptionase:# Exception是基类logging.exception(e)logerror()print('main')# IndexError: list index out of range# main
  1. raise手动触发异常
    主动抛出异常,在错误的地方中断程序并输出清晰地错误信息
defno_negative(num):ifnum<0:raiseValueError('No Negative!')returnnum no_negative(-1)# Traceback (most recent call last):# ValueError: No Negative!

这种raise的用法,更常用在网络请求、读取数据库时,如果有raise写入到log中就会非常清晰易懂。

总结:做一个小练习

# 运行下面的代码,根据异常信息进行分析,定位出错误源头,并修复:fromfunctoolsimportreducedefstr2num(s):returnint(s)defcalc(exp):ss=exp.split('+')ns=map(str2num,ss)returnreduce(lambdaacc,x:acc+x,ns)defmain():r=calc('100 + 200 + 345')print('100 + 200 + 345 =',r)r=calc('99 + 88 + 7.6')print('99 + 88 + 7.6 =',r)main()# 100 + 200 + 345 = 645# Traceback (most recent call last):# File "/home/bupt/python/python_basic.py", line 17, in <module># main()# File "/home/python/python_basic.py", line 14, in main# r = calc('99 + 88 + 7.6')# File "/home/python/python_basic.py", line 9, in calc# return reduce(lambda acc, x: acc + x, ns)# File "/home/python/python_basic.py", line 4, in str2num# return int(s)# ValueError: invalid literal for int() with base 10: ' 7.6'

从上往下分析错误信息,最后发现是str2num(s)函数调用的int(s)出错,不能转换7.6这个浮点数

调试器pdb

(以下为不依赖IDE的调试方式)

启动python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态:

s='0'n=int(s)print(10/n)

配置参数-m pdb命令行执行python程序:
python -m pdb python_basic.py
使用n单步执行,使用p 变量名查看变量的值

>/home/python/python_basic.py(1)<module>()->s='0'(Pdb)(Pdb)n# 使用 n 单步执行>/home/python/python_basic.py(2)<module>()->n=int(s)(Pdb)n>/home/python/python_basic.py(3)<module>()->print(10/ n)(Pdb)p s# 使用 p 查看变量'0'(Pdb)n ZeroDivisionError: division by zero>/home/python/python_basic.py(3)<module>()->print(10/ n)(Pdb)n --Return--

可以import pdb,使用pdb.trace()设置断点:

importpdb s='0'n=int(s)pdb.set_trace()print(10/n)

使用python python_basic.py运行程序,会自动在断点处暂停进入pdb调试环境,使用命令p查看变量,使用命令c继续运行:

$ python python_basic.py>/home/bupt/python/python_basic.py(5)<module>()->pdb.set_trace()(Pdb)p s'0'(Pdb)p n0(Pdb)c Traceback(most recent call last): File"/home/bupt/python/python_basic.py", line6,in<module>print(10/ n)~~~^~~ ZeroDivisionError: division by zero

Unittest单元测试

运行整套程序,检查哪里出错的测试方法只适合:小型项目/项目功能之间关联少的少量功能项目,否则,使用单元测试是更好的测试方法。

单元测试就是不直接测试全套程序逻辑,而是将小功能模块拆开逐个测试。在Python中,常用unittest测试框架做单元测试。

在class中继承unittest.TestCase,编写函数,以test开头的TestXxx类被认为是测试类,test_xxx方法被认为是测试方法
__main__函数中执行unittest.main(),这个“测试运行器”会自动发现并执行定义的测试类中所有的测试方法:

importunittestclassTestFunc(unittest.TestCase):deftest_example(self):self.assertEqual(2,divide(2,1))self.assertEqual(2,divide(-2,-1))# self.assertEqual(-1, divide(-2, 0))defdivide(a,b):returna/bif__name__=='__main__':unittest.main()# .# --------------------# Ran 1 test in 0.000s# OK

如果测试不通过,会报错:

self.assertEqual(-1,divide(-2,0))# return a / b# ~~^~~# ZeroDivisionError: division by zero# ---------------------------------------------------------------------# Ran 1 test in 0.000s# FAILED (errors=1)
  1. unittest规范
    可以先写unittest,然后再开发功能,类似于先设立目标,然后实现目标:
    比如想要:输入 1 返回 2,输入 -1 返回 3,输入其他任何数,返回 1。可以像下面一样先把test_func部分写好:
classTestFunc(unittest.TestCase):deftest_example(self):# 期望实现的功能self.assertEqual(2,my_func(1))self.assertEqual(3,my_func(-1))foriinrange(-100,100):ifi==1ori==-1:continueself.assertEqual(1,my_func(i))defmy_func(num):if__name__=='__main__':unittest.main()

测试文件要与原本的功能文件分开,测试文件以_test.py结尾,引入from all_my_func import my_func功能模块函数以进行测试,
可以同时测试多个功能模块:

defmy_func1(a):ifa==1:return2elifa==-1:return3else:return1defmy_func2(letter):ifletter=='yes':returnTrueelse:raiseValueError("Only YES!")classTestFunc(unittest.TestCase):deftest_func1(self):self.assertEqual(2,my_func1(1))self.assertEqual(3,my_func1(-1))foriinrange(-100,100):ifi==1ori==-1:continueself.assertEqual(1,my_func1(i))deftest_func2(self):self.assertTrue(my_func2('yes'))withself.assertRaises(ValueError):# 报错才能通过testmy_func2("nononono")if__name__=="__main__":unittest.main()# ..# ----------------------------------------------------------------------# Ran 2 tests in 0.000s# OK

通常将测试代码写在test.py文件中,在命令行使用python指令执行测试:
python -m unittest test.py

如果写出了很多的功能测试,但有时只想执行某一个test,可以进行如下替换:
但是这样写灵活性太差:

# unittest.main()suite=unittest.TestSuite()suite.addTest(TestFunc('test_func1'))unittest.TextTestRunner.run(suite)# .# ----------------------------------------------------------------------# Ran 1 test in 0.000s# OK

不如直接命令行执行对应参数命令来执行不同的test,灵活性更强:
python -m unittest testmodule.testclass.test_method

  1. setUp()&tearDown()
    在使用unittest进行单元测试时,可能需要前置准备后置清理
    -> 测试前需要准备数据,连接数据库,打开文件;
    -> 测试后需要清理数据,关闭数据库连接,删除临时文件
    为了避免在每一个测试方法中重复写这些准备和清理的代码,unittest提供了两个钩子方法:
  • setUp()
    在每个测试方法运行之前都会被自动调用
    用于创建测试所需要的环境或数据准备
  • tearDown()
    在每个测试方法运行之后都是被自动调用
    用于释放资源,清楚测试过程中产生的数据或恢复环境状态
importunittestclassTestExample(unittest.TestCase):defsetUp(self):print('setUp')returnsuper().setUp()deftearDown(self):print('tearDown')returnsuper().tearDown()deftest_fun1(self):print('test func 1')self.assertTrue(True)deftest_fun2(self):print('test func 2')self.assertEqual(1+1,2)if__name__=='__main__':unittest.main()# setUp# test func 1# tearDown# .setUp# test func 2# tearDown# .# ------------------------------------------# Ran 2 tests in 0.000s# OK

数据库连接场景:

defsetUp(self):self.conn=db.connect()self.cursor=self.conn.cursor()deftearDown(self):self.cursor.close()self.conn.close()

临时文件创建与删除:

defsetUp(self):self.file=open('temp.txt','w')deftearDown(self):self.file.close()os.remove('temp.txt')
  1. unittest断言方法列表
断言方法含义
assertEqual(a, b)判断a == b
assertNotEqual(a, b)判断a != b
assertTrue(condition)判断condition 是 True
assertFalse(condition)判断condition 是 False
assertGreater(a, b)判断a > b
assertGreaterEqual(a, b)判断a >= b
assertLess(a, b)判断a < b
assertLessEqual(a, b)判断a <= b
assertIs(a, b)判断a is b(是否是同一个对象
assertIsNot(a, b)判断a is not b(不是同一个对象)
assertIsNone(a)判断a is None
assertIsNotNone(a)判断a is not None
assertIn(a, b)判断a in b(a 是否在 b 中)
assertNotIn(a, b)判断a not in b(a 不在 b 中)
assertRaises(error)判断是否抛出了指定的异常(常与with一起使用)

异常/警告名称列表

异常名称描述
BaseException所有异常的基类
SystemExit解释器请求退出
KeyboardInterrupt用户中断执行(通常是 Ctrl+C)
Exception常规错误的基类
StopIteration迭代器没有更多的值
GeneratorExit生成器(generator)发生异常来通知退出
StandardError(Python 3 中已移除)所有内建标准异常的基类
ArithmeticError所有数值计算错误的基类
FloatingPointError浮点计算错误
OverflowError数值运算超出最大限制
ZeroDivisionError除以零或取模为零(适用于所有数据类型)
AssertionError断言语句失败
AttributeError对象没有该属性
EOFError没有内建输入,到达 EOF 标记
EnvironmentError(已合并进 OSError)操作系统错误的基类
IOError(Python 3中与 OSError 合并)输入/输出操作失败
OSError操作系统错误
WindowsError(仅限 Windows,Python 3 已移除)系统调用失败
ImportError导入模块/对象失败
LookupError无效数据查询的基类
IndexError序列中没有此索引
KeyError映射中没有这个键
MemoryError内存溢出错误(不是致命错误)
NameError未声明或未初始化的对象(变量不存在)
UnboundLocalError访问未初始化的本地变量
ReferenceError弱引用(weakref)试图访问已被回收的对象
RuntimeError一般的运行时错误
NotImplementedError尚未实现的方法
SyntaxErrorPython 语法错误
IndentationError缩进错误
TabErrorTab 与空格混用导致缩进错误
SystemError解释器系统错误
TypeError对类型无效的操作
ValueError传入无效参数(类型对但值不对)
UnicodeErrorUnicode 相关错误的基类
UnicodeDecodeErrorUnicode 解码错误
UnicodeEncodeErrorUnicode 编码错误
UnicodeTranslateErrorUnicode 转换错误
警告名称描述
Warning警告的基类
DeprecationWarning关于被弃用特性的警告
PendingDeprecationWarning将来某个版本会弃用的特性警告
FutureWarning构造将来语义可能会改变的警告
RuntimeWarning可疑的运行时行为警告
SyntaxWarning可疑的语法警告
UserWarning用户代码生成的警告
OverflowWarning(Python 2 使用,Python 3 已移除)自动转为 long 类型的旧警告
http://www.cnnetsun.cn/news/117302.html

相关文章:

  • 论文查重合格标准:从AI工具到学术规范的深度解析
  • 论文新手写作工具:9大AI工具推荐+步骤指南排名
  • 使用 pylintrc 配置 Python 代码检查的详细指南
  • 在 VS Code 中使用 Black 格式化 Python 代码
  • 文科查重率标准:8大平台+降重技巧排名
  • Lime编辑器:终极开源解决方案能否终结代码编辑器的选择困境?
  • 多模态舆情监测技术深度解析:Infoseek 如何实现 AI 造假与短视频舆情的精准捕捉?
  • 终极指南:如何快速掌握Admin.NET通用权限框架的10个核心技巧
  • 云端电子书制作新体验:EPubBuilder深度解析
  • GP2040-CE终极攻略:打造你的专属游戏控制神器
  • Matlab Simulink三相四桥臂逆变器仿真模型详解:电压外环电流内环控制,适应不平衡负...
  • 【数据集】上市公司-人工智能采纳程度测算数据(2003-2024年)
  • Uppy智能文件过滤:从混乱上传到精准控制的革命性方案
  • Nginx性能优化终极指南:Linux服务器加速实战技巧
  • AI销售自动化与客户管理的最佳获客软件选择--VertGrow AI销冠
  • Naive UI 图片预览实用技巧:打造专业画廊效果的高效方法
  • 前沿速递 | Adv. Eng. Mater.:基于LPBF与压力渗透的FeSi2.9-Bakelite多功能复合材料设计与性能调控
  • Mermaid Live Editor 终极指南:实时图表编辑的完整解决方案
  • Drawnix白板工具:用代码思维重塑图形设计工作流
  • Monaco Editor代码提示响应优化实战指南
  • 下一代前端开发:用Next.js与大模型AI,零代码解锁你的智能助手
  • 跨越浏览器壁垒:Skyvern如何实现自动化脚本的通用兼容性
  • 应用现代化 | 金融智能风控的新标尺——《金融级智能应用能力要求 风控场景》标准正式发布
  • Undetectable接入亮数据代理ip做自媒体矩阵
  • 如何用lidR包3步完成激光雷达林业精准分析:从点云到决策的完整指南
  • 初识操作系统
  • Android端AI模型部署终极指南:从入门到精通
  • RuoYi-Vue3企业级管理系统:现代化开发框架实战指南
  • MCP协议驱动企业级AI集成:芋道源码的智能化升级实践
  • 终极指南:使用gsplat.js实现高性能3D高斯点云渲染