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

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

  • 错误处理

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

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

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

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

try:
print 'try...'
r = 10 / 0
print '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 / n def main():
foo('')

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

  第三种,使用logging。

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

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

# err.py
import logging
logging.basicConfig(level=logging.INFO) s = ''
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 = ''
n = int(s)
print 10 / n

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

$ python -m pdb err.py
> /Users/michael/Github/sicp/err.py(2)<module>()
-> s = ''
(Pdb) l
1 # err.py
2 -> s = ''
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
''
(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 pdb s = ''
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 unittest

from mydict import Dict

class 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.000s OK

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

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

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

  • 文档测试

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

class Dict(dict):
'''
Simple dict but also support access as x.y style. >>> d1 = Dict()
>>> d1['x'] = 100
>>> d1.x
100
>>> 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.empty
Traceback (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] = value if __name__=='__main__':
import doctest
doctest.testmod()

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

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

Day-10: 错误、调试和测试的更多相关文章

  1. 转 Python3 错误和异常/ Python学习之错误调试和测试

    ########sample 0 https://www.cnblogs.com/Simon-xm/p/4073028.html except: #捕获所有异常 except: <异常名> ...

  2. 004-python面向对象,错误,调试和测试

    ---恢复内容开始--- 1.面向对象 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...

  3. Python:笔记(5)——错误、调试和测试

    Python:笔记(5)——错误.调试和测试 错误处理 1.TRY语句 这个和Java中的语法是及其相似的,catach换成except. 说明:同样,不管有没有错误,fianlly都会执行的! 补充 ...

  4. Visual Studio 原生开发的10个调试技巧(二)

    原文:Visual Studio 原生开发的10个调试技巧(二) 我以前关于 Visual Studio 调试技巧的文章引起了大家很大的兴趣,以至于我决定分享更多调试的知识.以下的列表中你可以看到写原 ...

  5. 11 . Python3之异常,调试和测试

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

  6. RFC2889错误帧过滤测试----网络测试仪实操

    一.简介 RFC 2889为LAN交换设备的基准测试提供了方法学,它将RFC 2544中为网络互联设备基准测试所定义的方法学扩展到了交换设备,提供了交换机转发性能(Forwarding Perform ...

  7. RabbitMQ调试与测试工具-v1.0.1 -提供下载测试与使用

    最近几天在看RabbitMQ,所以发了两天时间写了一个调试和测试工具.方便使用. 下载地址:RabbitMQTool-V1.0.1.zip

  8. 10个调试Java的技巧

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

  9. 【转】段错误调试神器 - Core Dump详解

    from:http://www.embeddedlinux.org.cn/html/jishuzixun/201307/08-2594.html 段错误调试神器 - Core Dump详解 来源:互联 ...

  10. C++多线程调试和测试的注意事项

    在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”.利用线程,用户可按下一个按钮,然后程序会立即作出响应,而不是让用户等待程序完成了当前任务以后才开 ...

随机推荐

  1. 如何将1234通过java变成4321,下面介绍几种办法。

    //1 StringBuffer的反转 public static void main(String[] args) { int a=1234; StringBuffer sb = new Strin ...

  2. MVC 网站部署常见问题汇总

    一:TGIShare项目是一个MVC5的网站程序,部署在了IIS上,使用的Windows验证方式,并在本机设置了计划任务定时调用某个地址执行命令.问题汇总如下: 1.Window Server 200 ...

  3. txt文件怎么设置默认打开是用这个EditPlus软件打开

    1.如果是正常安装的Editplus,只需要右击“txt文件”,在“打开方式”中选择“打开程序”,再点击“浏览”,找到“Editplus”打开,再将“始终使用选择的程序打开这种文件”前面的“口”选中, ...

  4. java 远程调用 RPC

    1. 概念 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).H ...

  5. mycat学习心得

    最近老大要求我们学习mycat,并运用到实际项目中.现在简单分享下自己的学习心得,也算是只是积累吧. 什么是mycat? 用我的话理解就是:mycat是一种技术,采用mycat后可以提高程序的速度,也 ...

  6. 怎样做才是最优雅方式切换 web 项目数据源 ?

    随着业务变迁/需求变更,JavaEE 应用中会被迫连接多个数据源进行业务处理. 怎样在不影响原有项目结构的情况下,已最优雅/最简洁的方式动态切换数据源呢? 本文已一次添加数据源后动态切换实践为例,描述 ...

  7. .NET定位CPU使用率过高问题

    摘要: 当一个.net应用在生产环境CPU突然居高不下,如何快速准确的定位问题所在,并且对实时业务影响最小化?如何不抓Dump也不用live debug就可以知道你的应用在做什么?如何确认你的应用是由 ...

  8. 利用JS做网页特效——大图轮播

    大图轮播完整流程代码操作: <style>            * {                margin: 0px;                padding: 0px;  ...

  9. MyBatis实现Mysql数据库分库分表操作和总结

    前言 作为一个数据库,作为数据库中的一张表,随着用户的增多随着时间的推移,总有一天,数据量会大到一个难以处理的地步.这时仅仅一张表的数据就已经超过了千万,无论是查询还是修改,对于它的操作都会很耗时,这 ...

  10. mybaits接口式编程

    Mybatis是接口式编程实现对.xml中sql语句的执行,其过程如下(取自慕课网视频<通过自动回复机器人学Mybatis---加强版>): 1.加载配置信息2.通过加载配置信息加载一个代 ...