程序运行时,会遇到各种各样的错误。

  编写错误叫做bug,而另一类由于运行过程中无法预测的,比如写文件时,磁盘满了,写不进去;或者从网络抓取数据,网络突然掉了。这些错误称为异常,程序中需要对异常进行处理,使得程序能够运行下去。

  • 错误处理

  Python中,程序运行错误时,如果错误没有捕获,它会一直往上抛,最后被Python解释器捕获,打印一个错误。

# err.py:
def foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():bar('0')main()

$ python err.py
Traceback (most recent call last):File "err.py", line 11, in <module>main()File "err.py", line 9, in mainbar('0')File "err.py", line 6, in barreturn foo(s) * 2File "err.py", line 3, in fooreturn 10 / int(s)
ZeroDivisionError: integer division or modulo by zero

从上到下,错误会一层层的反馈,直到显示最终出错的地方。

  try...except...finally...:常用这种方法来检查错误并捕捉到,同时进行相应的处理。

try:print 'try...'r = 10 / 0print 'result:', r
except ZeroDivisionError, e:print 'except:', e
finally:print 'finally...'
print 'END'

try...
except: integer division or modulo by zero
finally...
END

  注意到,错误类型有很多种,它们其实都是从BaseException类派生出来的,常见的错误类型和继承关系有:https://docs.python.org/2/library/exceptions.html#exception-hierarchy

  • 调试

  程序运行一次就成功的概率很小,基本上不超过1%。一般有如下的调试方法:

  第一种,直接在可能出错的地方print出来,但是后期会一个个删掉。

  第二种,使用断言来代替。

# err.py
def foo(s):n = int(s)assert n != 0, 'n is zero!'return 10 / ndef main():foo('0')

断言中,如果“n != 0”是错的,就抛出AssertionError,并显示后面的字符串。

  第三种,使用logging。

  logging有debug,info,warning,error等几个级别,从前到后优先级依次提高,即如果,指定level=WARNING后,debug和info就不起作用了。这样一样,就可以输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。

  logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,,比如console和文件。

# err.py
import logginglogging.basicConfig(level=logging.INFO)s = '0'
n = int(s)
logging.info('n = %d' % n)
print 10 / n

$ python err.py
INFO:root:n = 0
Traceback (most recent call last):File "err.py", line 8, in <module>print 10 / n
ZeroDivisionError: integer division or modulo by zero

  第四种调试方式,就是调试器pdb,让程序以单步方式运行,可以随时查看运行状态。

# err.py
s = '0'
n = int(s)
print 10 / n

然后,以参数-m pdb启动,单步运行

$ python -m pdb err.py
> /Users/michael/Github/sicp/err.py(2)<module>()
-> s = '0'

(Pdb) l1     # err.py2  -> s = '0'3     n = int(s)4     print 10 / n
[EOF]

输入n单步运行下一步

(Pdb) n
> /Users/michael/Github/sicp/err.py(3)<module>()
-> n = int(s)
(Pdb) n
> /Users/michael/Github/sicp/err.py(4)<module>()
-> print 10 / n

输入p 变量名来查看变量状态。

(Pdb) p s
'0'
(Pdb) p n
0

输入q结束运行

(Pdb) n
ZeroDivisionError: 'integer division or modulo by zero'
> /Users/michael/Github/sicp/err.py(4)<module>()
-> print 10 / n
(Pdb) q

  另外在合适的地方,设置pdb.set_trace(),可以作为断点。

# err.py
import pdbs = '0'
n = int(s)
pdb.set_trace() # 运行到这里会自动暂停
print 10 / n

$ python err.py
> /Users/michael/Github/sicp/err.py(7)<module>()
-> print 10 / n
(Pdb) p n
0
(Pdb) c
Traceback (most recent call last):File "err.py", line 7, in <module>print 10 / n
ZeroDivisionError: integer division or modulo by zero

到达断点时,进入pdb调试器。

  最后,还有方便的IDE调试器。

  • 单元测试

  单元测试,顾名思义,就是对一个部分测试,可以是一个模块、一个函数或者一个类。它的目的是保证该单元能够实现原先规划的功能,为之后的整体调试做准备。

  例如,现有模块mydict.py,对它的要求是实现如下功能:

>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1

mydict.py代码如下:

class Dict(dict):def __init__(self, **kw):super(Dict, self).__init__(**kw)def __getattr__(self, key):try:return self[key]except KeyError:raise AttributeError(r"'Dict' object has no attribute '%s'" % key)def __setattr__(self, key, value):self[key] = value

编写的单元测试,需要引入unittest模块,编写的mydict_test.py如下:

import unittestfrom mydict import Dictclass TestDict(unittest.TestCase):def test_init(self):  # 测试初始化功能d = Dict(a=1, b='test')self.assertEquals(d.a, 1)self.assertEquals(d.b, 'test')self.assertTrue(isinstance(d, dict))def test_key(self):  # 测试key的功能d = Dict()d['key'] = 'value'self.assertEquals(d.key, 'value')def test_attr(self):  # 测试属性功能d = Dict()d.key = 'value'self.assertTrue('key' in d)self.assertEquals(d['key'], 'value')def test_keyerror(self):  # 测试key错误的功能d = Dict()with self.assertRaises(KeyError):value = d['empty']def test_attrerror(self):  # 测试属性错误的功能d = Dict()with self.assertRaises(AttributeError):value = d.empty

  编写的单元测试类,从unittest.TestCase继承。其中,只有以test开头的方法是测试方法。

  运行单元测试时,可以在测试文件中加入:

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

然后run。

  另一种,在命令行中输入命令:

$ python -m unittest mydict_test
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000sOK

第二种方法,可以一次运行多个测试文件,比较方便。

  setUp与tearDown:在每个测试方法前后分别被执行,避免在测试代码中重复加入代码。

  最后,单元测试要考虑到异常,代码不能过于复杂,以免本身就有bug。

  • 文档测试

  Python中可以提供实例文档,在文件中编写特定格式的注释,调用doctest判断程序是否会像注释中那样的运行。

class Dict(dict):'''Simple dict but also support access as x.y style.>>> d1 = Dict()>>> d1['x'] = 100>>> d1.x100>>> d1.y = 200>>> d1['y']200>>> d2 = Dict(a=1, b=2, c='3')>>> d2.c'3'>>> d2['empty']Traceback (most recent call last):...KeyError: 'empty'>>> d2.emptyTraceback (most recent call last):...AttributeError: 'Dict' object has no attribute 'empty''''def __init__(self, **kw):super(Dict, self).__init__(**kw)def __getattr__(self, key):try:return self[key]except KeyError:raise AttributeError(r"'Dict' object has no attribute '%s'" % key)def __setattr__(self, key, value):self[key] = valueif __name__=='__main__':import doctestdoctest.testmod()

然后run。如果什么都没输出,就说明编写的doctest运行都是正确的。

注:本文为学习廖雪峰Python入门整理后的笔记

转载于:https://www.cnblogs.com/likely-kan/p/7517924.html

Day-10: 错误、调试和测试相关推荐

  1. error 系统错误 错误码10007_Python学习之错误调试和测试

    Python学习之错误调试和测试 Python学习目录 在Mac下使用Python3 Python学习之数据类型 Python学习之函数 Python学习之高级特性 Python学习之函数式编程 Py ...

  2. cfree运行程序错误的原因_Python入门教程 | 第 8 章 错误、调试和测试

    第八章 错误.调试和测试 在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的. 有的错误 ...

  3. 硬件测试含软件调试,硬件调试与测试规范.doc

    第 PAGE i页 硬件调试与测试规范 目录 TOC \o "1-3" \h \z 前言 3 1参考标准 3 2适用范围 3 3硬件调试与测试规范 3 3.1硬件测试流程细则 3 ...

  4. Nginx 附录C 模块编译,调试与测试

    Nginx 附录C 模块编译,调试与测试 C.1 编译与安装 环境要求 操作系统:目前Nginx各版本在以下操作系统和平台测试通过: FreeBSD 3 - 10 / i386; FreeBSD 5 ...

  5. WEB十大安全漏洞(OWASP Top 10)与渗透测试记录

    1. 前言 每年 OWASP(开放 Web 应用程序安全项目)都会发布十大安全漏洞.它代表了对 Web 应用程序最关键的安全风险的广泛共识.了解十大WEB漏洞种类并善于在渗透测试中发现漏洞是安全行业人 ...

  6. 几种Linux段错误调试方法

    一.产生段错误的原因 段错误就是指某一进程访问了不属于它权限范围的内存空间,比如:访问了不存在的内存,访问了受系统保护的内存,访问了只读的内存等.下面是一段会产生段错误的实例代码:main.c #in ...

  7. git.exe init#timeout = 10错误:克隆远程repo'origin'时出错hudson.plugins.git

    用Jenkins自动化搭建测试环境,Jenkins构建任务 关键异常抓取 git.exe init#timeout = 10错误:克隆远程repo'origin'时出错hudson.plugins.g ...

  8. 并行程序调试、测试与模型检测

    并行程序调试.测试与模型检测 并行程序调试的挑战: 1.由于不能确定不同线程的执行顺序,导致可能的执行路径发生组合爆炸: 2.使用模型检验程序正确性能以应用到分布式系统上. 名词解释 确定性重放:通过 ...

  9. 正确理解以下名词及其含义1源程序,目标程序,可执行程序2程序编辑,程序编译,程序连接3程序,程序模块,程序文件4函数,主函数,被调用函数,库函数5程序调试,程序测试

    正确理解以下名词及其含义: (1)源程序,目标程序,可执行程序. 源程序:指未编译的按照一定的程序设计语言规范书写的文本文件,是一系列人类可读的计算机语言指令目标程序:为源程序经编译可直接被计算机运行 ...

  10. Java程序员应该知道的10个调试技巧

    摘要:调试不仅可以查找到应用程序缺陷所在,还可以解决缺陷.对于Java程序员来说,他们不仅要学会如何在Eclipse里面开发像样的程序,更需要学会如何调试程序.本文介绍了Java程序员必知的10个调试 ...

最新文章

  1. 重构职场竞争力之测试能力提升方法
  2. Mac下安装JDK以及怎么配置环境变量?
  3. 计算机除法和取余在实际运用中的意义
  4. 查看Servlet 3.0的新增功能
  5. 函数的自执行,变量提升和函数提升
  6. 前端学习(1154):常量const02
  7. java关键字:volatile
  8. 利用Python制作一个“电子记事本”
  9. Git:查看所有远程分支以及同步远程代码
  10. 升级成员服务器-从Windows 2012升级到2016案例之2
  11. 请简述java的异常体系,Java的异常体系 面试题
  12. python创建子窗口_python GUI编程(Tkinter) 创建子窗口及在窗口上用图片绘图实例
  13. 服务封装软件 nssm
  14. Java之力[从蛮荒到撬动地球]之设计模式
  15. 码易手机站,现已轻快上线!
  16. 与10.110.12.30 mask 255.255.255.224属于同一网段的主机IP地址是?
  17. 排序算法大比拼(2.2)——时间O(n log2n)篇之快速排序(左右指针法)
  18. Android移动开发-Android开发日历时常用的农历和公历换算代码工具类
  19. C#做一个简单浏览器
  20. IDEA之翻译器的妙用Translation

热门文章

  1. java中exec命令,java - 从Java中运行exec命令需要 bash 吗? - SO中文参考 - www.soinside.com...
  2. 什么是 restful api
  3. 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案(一)
  4. 9适应之力加多少攻击_剑盾铠之孤岛DLC新增内容大全! 宝可梦史上第一款DLC到底香不香(含试玩视频)...
  5. Nginx开发一个简单的HTTP过滤模块
  6. 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符
  7. opencv之图象裁剪
  8. centos中的配置文件
  9. Scala入门到精通——第四节 Set、Map、Tuple、队列操作实战
  10. 处理 Maven 项目名称红色感叹号的问题