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练习程序批量修改文件名
Jan 16 Python
pyqt4教程之实现windows窗口小示例分享
Mar 07 Python
python实现字符串和字典的转换
Sep 29 Python
Django-Rest-Framework 权限管理源码浅析(小结)
Nov 12 Python
python3 实现一行输入,空格隔开的示例
Nov 14 Python
python之信息加密题目详解
Jun 26 Python
python利用7z批量解压rar的实现
Aug 07 Python
tensorflow 模型权重导出实例
Jan 24 Python
详解有关PyCharm安装库失败的问题的解决方法
Feb 02 Python
使用BeautifulSoup4解析XML的方法小结
Dec 07 Python
selenium设置浏览器为headless无头模式(Chrome和Firefox)
Jan 08 Python
python用700行代码实现http客户端
Jan 14 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 has encountered an Access Violation
2007/01/15 PHP
配置Apache2.2+PHP5+CakePHP1.2+MySQL5运行环境
2009/04/25 PHP
深入解析Session是否必须依赖Cookie
2013/08/02 PHP
自己写的兼容低于PHP 5.5版本的array_column()函数
2014/10/24 PHP
php实现的简单日志写入函数
2015/03/31 PHP
100多行PHP代码实现socks5代理服务器[2]
2016/05/05 PHP
PHP基于新浪IP库获取IP详细地址的方法
2017/05/04 PHP
Yii2.0框架behaviors方法使用实例分析
2019/09/30 PHP
Javascript 通过json自动生成Dom的代码
2010/04/01 Javascript
把文本中的URL地址转换为可点击链接的JavaScript、PHP自定义函数
2014/07/29 Javascript
jQuery实现数字加减效果汇总
2014/12/16 Javascript
基于jquery实现省市联动效果
2015/11/23 Javascript
jQuery on()方法绑定动态元素的点击事件无响应的解决办法
2016/07/07 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
jQuery实现根据生日计算年龄 星座 生肖
2016/11/23 Javascript
jquery-mobile表单的创建方法详解
2016/11/23 Javascript
微信小程序 页面跳转和数据传递实例详解
2017/01/19 Javascript
Node.js中看JavaScript的引用
2017/04/22 Javascript
详解如何在你的Vue项目配置vux
2018/06/04 Javascript
React key值的作用和使用详解
2018/08/23 Javascript
VUE注册全局组件和局部组件过程解析
2019/10/10 Javascript
深入解析Python编程中super关键字的用法
2016/06/24 Python
python Socket之客户端和服务端握手详解
2017/09/18 Python
完美解决python中ndarray 默认用科学计数法显示的问题
2018/07/14 Python
Python实现Linux监控的方法
2019/05/16 Python
python实现单目标、多目标、多尺度、自定义特征的KCF跟踪算法(实例代码)
2020/01/08 Python
使用pytorch 筛选出一定范围的值
2020/06/28 Python
PyQt5-QDateEdit的简单使用操作
2020/07/12 Python
python map比for循环快在哪
2020/09/21 Python
电子商务个人职业生涯规划范文
2014/02/12 职场文书
2014全国两会心得体会
2014/03/17 职场文书
老乡聚会通知
2015/04/23 职场文书
2015年幼儿园德育工作总结
2015/05/25 职场文书
2015年秋学期教研工作总结
2015/10/14 职场文书
HTML5 新增内容和 API详解
2021/11/17 HTML / CSS
对讲机知识
2022/04/07 无线电