错误处理
Python中的try
try:
...
except 错误类型1 as e:
...
except 错误类型2:
...
else:
...
finally: #可缺省,一定会被执行
....
- `try…except“`可以跨越多层调用,这是一个极大的便利;
- 所有的错误类型都继承自错误基类
BaseException
,捕捉到的错误类型会将这种类型的子类也全部捕获,因此如果一个exception错误类型后还有一个exception子类错误类型,则后者不会被捕获。
打印调用堆栈
先import logging
,再在except块中使logging.exception(e)
,则可以将错误堆栈打印出,然后继续执行程序。也可以将以上信息写入文件,实现方法在IO一章再做整理。
抛出错误
如果要自己定义错误类型FooError,则要设置好它继承自哪一个父类,然后用raise FooError(...)
抛出错误。不过尽量用Python内置的错误类型。raise
语句如果不带参数,会把当前错误原样抛出,让上一级调用处理。
调试
断言经常用在调试中,python的断言格式是assert 表达式
。而且Python有个方法可以跳过所有断言$ python3 -O err.py
其中的参数-0
就是跳过断言的解释器启动参数
logging
上一节提到logging可以记录和输出错误,使用logging调试显然也是可以的。可以使用logging.info(...)
输出调试信息,而且logging有个功能,在import logging
下一行添加logging basicConfig(level = logging.INFO)
可以定义信息处理的级别,如debug
, info
, warning
, error
等。低于该级别的信息就不会起作用了。
其他方法
至于更多的调试方法,比如单步运行等,还是使用IDE方便,这里就不整理了
单元测试
- 单元测试需要首先
import unittest
。 - 还要引入需要测试的类或函数。
- 然后定义一个单元测试类,从
unittest.TestCase
父类继承,并且包含各种测试方法。 - 测试方法需要以
test_
开头。一般使用不同形式的断言来判断结果,如self.assertTrue(...)
、self.assertEqual(...)
等。还可以抛出指定断言错误:
#抛出表达式对应的错误
with self.assertRaises(错误类型):
表达式
运行单元测试
在在单元测试的模块最后加上下列代码:
if __name__ = '__main__':
unittest.main()
这样就可以把该模块内的代码作为正常Python脚本运行。
在命令行中使用$ python3 -m unittest 测试模块名
可以更方便地运行单元测试,而且可以实现批量单元测试
两个用于单元测试的特殊函数
setUp()
和tearDown()
,在每调用一个测试方法的前后被执行。这样就可以将文件读写等操作放到这两个函数里,简化其他方法的代码。
文档测试
执行写在注释里的代码。Python内置的文档测试doctest模块可以直接提取主时钟的代码并执行测试。比如下面对阶乘函数进行文档测试的代码:
#fdt.py
def fact(n):
'''
test fact function
>>> fact(1)
1
>>> fact(0)
Traceback (most recent call last):
...
ValueError: '0'
>>> fact(-1)
Traceback (most recent call last):
...
ValueError: '-1'
>>> fact(2)
2
>>> fact(5)
120
'''
if n < 1:
raise ValueError()
if n == 1:
return 1
return n*fact(n-1)
if __name__ == '__main__':
import doctest
doctest.testmod()
在命令行中执行,将会输出测试的信息。在根据教程编写这段程序的时候执行遇到了大量错误,最后发现是一个非常细节的地方没注意到:
文档测试的注释部分,>>>
后边一定要有个空格再写东西:>>> fact(1)
空格一定不能少