python错误调试及单元文档测试过程解析


Posted in Python onDecember 19, 2019

这篇文章主要介绍了python错误调试及单元文档测试过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

错误分为程序的错误和由用户错误的输入引起的错误,此外还有因为各种各样意外的情况导致的错误,比如在磁盘满的时候写入、从网络爬取东西的时候,网络断了。这类错误称为异常

错误处理

普通的错误处理机制就是在出错的时候返回一个错误代码,但是这样十分不方便,一是因为错误码是和正常结果一样的方式返回的,判断起来十分不方便,二是错误还需要一级一级的向上报,直到错误处理程序。

所以高级语言通常都内置了一套 try...except...finally... 的错误处理机制,Python也不例外。

try:
  A#如果A中的代码执行过程中出错,就会执行B中的代码
except ZeroDivisionError as e:
  B
finally:
  C#C中的代码无论是否出错都会正常执行(可以不要这个)<br>。。。

如果错误有不同的类型,可以说使用多个except语句,每个语句处理一个类型的错误

另外,可以在except后面加一个else,如果没有出错,会执行else

Python 的错误其实也是一个类,所有的异常类型都是从BaseException类派生的

except在捕获错误时,不但捕获该类型的错误,而且还会把子类一网打尽

try:
  foo()
except ValueError as e:
  print('ValueError')
except UnicodeError as e:
  print('UnicodeError')
#第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。

使用try...except还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理。也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。

记录错误

如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

Python内置的logging模块可以非常容易地记录错误信息

通过配置,logging还可以把错误记录到日志文件里,方便事后排查。

抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例

只有在有必要的时候才定义我们自己的错误

另外一种错误处理

在try...excep捕获到异常后,还可以在except中使用 'raise‘把异常抛出去,以便于上级处理,如果raise语句不带参数,就会把异常原样抛出去,我们还可以通过raise 跟一个别的异常类型来将一种错误的类型转化为另外一种类型如:

try:
  10 / 0
except ZeroDivisionError:
  raise ValueError('input error!')

这种类型应该是一种合理的类型,而不应该将一种类型转化为另外一种不相干的类型

程序也可以主动抛出错误,让调用者来处理相应的错误。但是,应该在文档中写清楚可能会抛出哪些错误,以及错误产生的原因。

调试

断言

我们有事再调试的时候为了省事,就直接由print打印出变量的值,断言的作用和上面一样,凡是可以用print来辅助查看的地方,都可以用断言替代

断言可以加提示信息,

def foo(s):
  n = int(s)
  assert n != 0, 'n is zero!'#检查n是否是0,返回bool
  return 10 / n
 
def main():
  foo('0')

如果断言失败,assert语句本身就会抛出AssertionError:提示信息

启动Python解释器时可以用-O参数来关闭assert:

$ python -O err.py

使用pdb方式来调试

python -m pdb fortest.py#使用-m pdb 来启动调试
l #使用l来查看代码
n #使用n来执行一行代码
p 变量名#任何时候都可以输入p加变量名来查看变量
q#使用q退出

pdb.set_trace()

这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点:

运行代码,程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行:

IDE

虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。

单元测试

为什么编写单元测试呢,因为在写好的程序可能在以后还需要修改,这时如果由单元测试,我们就能够保证修改后的程序在功能上和以前的相同,这一定程度上也减少了测试的繁杂性

这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。

接下来,作者举了一个例子来介绍了单元测试的编写模式,并且介绍了一些用到的函数

我们需要引入Python自带的测试模块unittest模块

import unittest

编写单元测试的时候,需要编写一个测试类,这个类从unittest.TestCase派生

def TestDict(unittest.TestCase):
  def test_init(self):
    pass

以test开头的方法就是测试方法,不以test开头的方法就不被认为是测试方法,运行单元测试的时候不会被执行

对每一类测试都需要编写一个测试方法,由于unittest.TestCase内置了很多判断,我们只需要断言这些输出是否是我们所需要的,最常用的断言就是assertEqual(),

self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
另一种重要的断言就是期待抛出指定类型的Error,比如通过d['empty']访问不存在的key时,断言会抛出KeyError:

with self.assertRaises(KeyError):
  value = d['empty']

运行单元测试

两种方法,一种直接在模块中加入

if __name__ == '__main__':
unittest.main()

另一种方法是在命令行通过参数-m unittest直接运行单元测试

这是推荐的做法,因为这样可以一次批量运行很多单元测试,并且,有很多工具可以自动来运行这些单元测试。

setUp和tearDown

这两个函数可以写在测试类中,作用就是再每个测试方法被调用之前会执行setUp(),被调用之后会执行tearDown(),可以把一些准备工作、和善后工作放到这些函数中。

  • 单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。
  • 单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。
  • 单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。
  • 单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。

文档测试

文档测试就是运行写在注释中的实例代码

文档测试不能再调试(Debugger)模式下运行,否则会报错

PYDEV DEBUGGER WARNING:
sys.settrace() should not be used when the debugger is being used.
This may cause the debugger to stop working correctly.
If this is needed, please check:
http://pydev.blogspot.com/2007/06/why-cant-pydev-debugger-work-with.html
to see how to restore the debug tracing back correctly.
Call Location:
 File "c:\users\administrator.sc-201605202132\appdata\local\programs\python\python36\Lib\doctest.py", line 1480, in run
  sys.settrace(save_trace)

很多文档都有示例代码,可以把这些示例代码在Python的交互环境下运行。这些代码与其他说明可以写在注释中,然后,由一些工具来自动生成文档

def abs(n):
  '''
  Function to get absolute value of number.
   
  Example:
   
  >>> abs(1)
  1
  >>> abs(-1)
  1
  >>> abs(0)
  0
  '''
  return n if n >= 0 else (-n)

无疑更明确地告诉函数的调用者该函数的期望输入和输出。并且,Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。

doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候(即真正运行的结果和实例代码中的结果不一样的时候,就会报错),可以用...表示中间一大段烦人的输出。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python求众数问题实例
Sep 26 Python
Python脚本在Appium库上对移动应用实现自动化测试
Apr 17 Python
Python标准库06之子进程 (subprocess包) 详解
Dec 07 Python
Python  pip安装lxml出错的问题解决办法
Feb 10 Python
安装Python和pygame及相应的环境变量配置(图文教程)
Jun 04 Python
使用Python实现在Windows下安装Django
Oct 17 Python
Python实现的远程文件自动打包并下载功能示例
Jul 12 Python
Django 缓存配置Redis使用详解
Jul 23 Python
Python安装whl文件过程图解
Feb 18 Python
django-利用session机制实现唯一登录的例子
Mar 16 Python
python3 循环读取excel文件并写入json操作
Jul 14 Python
python 镜像环境搭建总结
Sep 23 Python
Python3.5 win10环境下导入kera/tensorflow报错的解决方法
Dec 19 #Python
解决Python列表字符不区分大小写的问题
Dec 19 #Python
简单了解为什么python函数后有多个括号
Dec 19 #Python
解决Python使用列表副本的问题
Dec 19 #Python
python读写Excel表格的实例代码(简单实用)
Dec 19 #Python
python装饰器原理与用法深入详解
Dec 19 #Python
python列表生成器迭代器实例解析
Dec 19 #Python
You might like
提升PHP执行速度全攻略(上)
2006/10/09 PHP
使用VisualStudio开发php的图文设置方法
2010/08/21 PHP
PHP基于单例模式实现的数据库操作基类
2016/01/15 PHP
php文件缓存方法总结
2016/03/16 PHP
PHP上传Excel文件导入数据到MySQL数据库示例
2016/10/25 PHP
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
异步javascript的原理和实现技巧介绍
2012/11/08 Javascript
caller和callee的区别介绍及演示结果
2013/03/10 Javascript
跟我学习javascript创建对象(类)的8种方法
2015/11/20 Javascript
javascript设计模式Constructor(构造器)模式
2016/08/19 Javascript
js实现带缓动动画的导航栏效果
2017/01/16 Javascript
JavaScript实现鼠标点击导航栏变色特效
2017/02/08 Javascript
vue中SPA单页面应用程序详解
2017/11/07 Javascript
Vue中的slot使用插槽分发内容的方法
2018/03/01 Javascript
jQuery实现每隔一段时间自动更换样式的方法分析
2018/05/03 jQuery
JS获取浏览器地址栏的多个参数值的任意值实例代码
2018/07/24 Javascript
vue中设置height:100%无效的问题及解决方法
2018/07/27 Javascript
简单易扩展可控性强的Jquery转盘抽奖程序
2019/03/16 jQuery
Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)
2019/12/04 Javascript
python处理图片之PIL模块简单使用方法
2015/05/11 Python
Python使用PIL模块生成随机验证码
2017/11/21 Python
Flask使用Pyecharts在单个页面展示多个图表的方法
2019/08/05 Python
Python Lambda函数使用总结详解
2019/12/11 Python
python识别验证码图片实例详解
2020/02/17 Python
python可迭代对象去重实例
2020/05/15 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
2021/03/04 Python
HTML5 Plus 实现手机APP拍照或相册选择图片上传功能
2016/07/13 HTML / CSS
俄罗斯最大的在线手表商店:Bestwatch.ru
2020/01/11 全球购物
巴西24小时在线药房:Droga Raia
2020/05/12 全球购物
法人授权委托书格式
2014/04/08 职场文书
学生手册评语
2014/05/05 职场文书
联谊活动总结范文
2015/05/09 职场文书
毕业论文致谢词
2015/05/14 职场文书
党员转正介绍人意见
2015/06/03 职场文书
Python词云的正确实现方法实例
2021/05/08 Python
Python中Cookies导出某站用户数据的方法
2021/05/17 Python