< 笔记 > Python
来源:互联网 发布:blog域名注册 编辑:程序博客网 时间:2024/06/05 07:52
09 Python 错误调试测试
By Kevin Song
- 09-01 错误处理
- 09-02 调试
- 09-03 单元测试
- 09-04 文档测试
09-01 错误处理
try…except…finally…
try: print('try...') r = 10 / 0 print('result:', r)except ZeroDivisionError as e: print('except:', e)finally: print('finally...')print('END')
try...except: division by zerofinally...END
- 执行try内语句,如果出错,后续代码不会继续执行,直接跳转至except
- 执行except
- 执行finally
多种类型的错误
多个except捕获不同类型的错误
try: print('try...') r = 10 / int('a') print('result:', r)except ValueError as e: print('ValueError:', e)except ZeroDivisionError as e: print('ZeroDivisionError:', e)finally: print('finally...')print('END')
如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句
try: print('try...') r = 10 / int('2') print('result:', r)except ValueError as e: print('ValueError:', e)except ZeroDivisionError as e: print('ZeroDivisionError:', e)else: print('no error!')finally: print('finally...')print('END')
所有的错误类型都继承自 BaseException:https://docs.python.org/3/library/exceptions.html#exception-hierarchy
下面代码第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了
try: foo()except ValueError as e: print('ValueError')except UnicodeError as e: print('UnicodeError')
优点:不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了
def foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): try: bar('0') except Exception as e: print('Error:', e) finally: print('finally...')
调用堆栈
如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出
# err.py:def foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): bar('0')main()
$ python3 err.pyTraceback (most recent call last): File "err.py", line 11, in <module> main() File "err.py", line 9, in main bar('0') File "err.py", line 6, in bar return foo(s) * 2 File "err.py", line 3, in foo return 10 / int(s)ZeroDivisionError: division by zero
记录错误
Python内置的logging模块可以非常容易地记录错误信息
# err_logging.pyimport loggingdef foo(s): return 10 / int(s)def bar(s): return foo(s) * 2def main(): try: bar('0') except Exception as e: logging.exception(e)main()print('END')
同样是出错,但程序打印完错误信息后会继续执行,并正常退出:
$ python3 err_logging.pyERROR:root:division by zeroTraceback (most recent call last): File "err_logging.py", line 13, in main bar('0') File "err_logging.py", line 9, in bar return foo(s) * 2 File "err_logging.py", line 6, in foo return 10 / int(s)ZeroDivisionError: division by zeroEND
抛出错误
- 定义错误的class
- 选择继承关系
- raise抛出一个错误的实例
# err_raise.pyclass FooError(ValueError): passdef foo(s): n = int(s) if n==0: raise FooError('invalid value: %s' % s) return 10 / nfoo('0')
一层一层抛出
# err_reraise.pydef foo(s): n = int(s) if n==0: raise ValueError('invalid value: %s' % s) return 10 / ndef bar(): try: foo('0') except ValueError as e: print('ValueError!') raisebar()
注意: raise语句如果不带参数,就会把当前错误原样抛出
在except中raise一个Error,可以把一种类型的错误转化成另一种类型
try: 10 / 0except ZeroDivisionError: raise ValueError('input error!')
注意:转换必须合理,不应该把一个IOError转换成毫不相干的ValueError
09-02 调试
调试方法一:直接打印
def foo(s): n = int(s) print('>>> n = %d' % n) return 10 / ndef main(): foo('0')main()
$ python3 err.py>>> n = 0Traceback (most recent call last): ...ZeroDivisionError: integer division or modulo by zero
缺点:调试完毕需要手动删除print
调试方法二:断言(assert)
格式:assert 表达式1, 表达式2
- 表达式1:返回布尔型
- 表达式2:断言失败时输出的失败消息的字符串
def foo(s): n = int(s) assert n != 0, 'n is zero!' return 10 / ndef main(): foo('0')
断言失败
$ python3 err.pyTraceback (most recent call last): ...AssertionError: n is zero!
启动Python解释器时可以用-O参数来关闭assert,关闭后,所有的assert相当于pass
调试方法三:logging
和assert比,logging不会抛出错误,而且可以输出到文件
import logginglogging.basicConfig(level=logging.INFO)s = '0'n = int(s)logging.info('n = %d' % n)print(10 / n)
记录信息的级别
- debug
- info:level=logging.INFO
- warning
- error
调试方法三:pdb
作用:让程序以单步方式运行,可以随时查看运行状态
# err.pys = '0'n = int(s)print(10 / n)
启动pdb
$ python3 -m pdb err.py> /Users/michael/Github/learn-python3/samples/debug/err.py(2)<module>()-> s = '0'
输入命令 l 查看代码
(Pdb) l 1 # err.py 2 -> s = '0' 3 n = int(s) 4 print(10 / n)
输入命令 n 单步执行代码
(Pdb) n> /Users/michael/Github/learn-python3/samples/debug/err.py(3)<module>()-> n = int(s)(Pdb) n> /Users/michael/Github/learn-python3/samples/debug/err.py(4)<module>()-> print(10 / n)
输入命令 p 变量名 查看变量
(Pdb) p s'0'(Pdb) p n0
输入命令 q 结束调试
(Pdb) q
调试方法四:pdb.set_trace()
不需要单步执行的pdb
- import pdb
- 在可能出错的地方放一个pdb.set_trace()(设置断点)
# err.pyimport pdbs = '0'n = int(s)pdb.set_trace() # 运行到这里会自动暂停print(10 / n)
程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行
$ python3 err.py > /Users/michael/Github/learn-python3/samples/debug/err.py(7)<module>()-> print(10 / n)(Pdb) p n0(Pdb) cTraceback (most recent call last): File "err.py", line 7, in <module> print(10 / n)ZeroDivisionError: division by zero
09-03 单元测试
类似于Codewars的attempt
定义:用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作
编写Dict类:mydict.py
class Dict(dict): def __init__(self, **kw): super().__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
编写mydict_test.py
import unittestfrom mydict import Dictclass TestDict(unittest.TestCase): def test_init(self): d = Dict(a=1, b='test') self.assertEqual(d.a, 1) self.assertEqual(d.b, 'test') self.assertTrue(isinstance(d, dict)) def test_key(self): d = Dict() d['key'] = 'value' self.assertEqual(d.key, 'value') def test_attr(self): d = Dict() d.key = 'value' self.assertTrue('key' in d) self.assertEqual(d['key'], 'value') def test_keyerror(self): d = Dict() with self.assertRaises(KeyError): value = d['empty'] def test_attrerror(self): d = Dict() with self.assertRaises(AttributeError): value = d.empty
每一类测试都需要编写一个test_xxx()方法,unittest.TestCase提供了很多内置的条件判断,调用这些方法就可以断言输出结果
相等断言:assertEqual()
self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
抛出指定类型的Error断言:assertRaises()
通过d[‘empty’]访问不存在的key时,断言会抛出KeyError
with self.assertRaises(KeyError): value = d['empty']
通过d.empty访问不存在的key时,期待抛出AttributeError
with self.assertRaises(AttributeError): value = d.empty
运行单元测试
方法一: 在mydict_test.py的最后加上两行代码:
if __name__ == '__main__': unittest.main()
$ python3 mydict_test.py
方法二: 在命令行通过参数-m unittest直接运行单元测试
$ python3 -m unittest mydict_test.....-----------------------------------------------------------------Ran 5 tests in 0.000sOK
setUp与tearDown
setUp与tearDown这两个方法会分别在每调用一个测试方法的前后分别被执行
示例:测试需要启动一个数据库,这时,就可以在setUp()方法中连接数据库,在tearDown()方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:
class TestDict(unittest.TestCase): def setUp(self): print('setUp...') def tearDown(self): print('tearDown...')
09-04 文档测试
自动执行写在注释中的代码
# mydict2.pyclass 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] = valueif __name__=='__main__': import doctest doctest.testmod()
运行python3 mydict2.py:
$ python3 mydict2.py
什么输出也没有。说明编写的doctest运行都是正确的。如果程序有问题,比如把getattr()方法注释掉,再运行就会报错:
$ python3 mydict2.py**********************************************************************File "/Users/michael/Github/learn-python3/samples/debug/mydict2.py", line 10, in __main__.DictFailed example: d1.xException raised: Traceback (most recent call last): ... AttributeError: 'Dict' object has no attribute 'x'**********************************************************************File "/Users/michael/Github/learn-python3/samples/debug/mydict2.py", line 16, in __main__.DictFailed example: d2.cException raised: Traceback (most recent call last): ... AttributeError: 'Dict' object has no attribute 'c'**********************************************************************1 items had failures: 2 of 9 in __main__.Dict***Test Failed*** 2 failures.
当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行
- Python笔记
- python笔记
- python笔记
- python笔记
- python笔记
- PYTHON笔记
- python笔记
- python笔记
- python笔记
- Python笔记
- Python笔记
- Python笔记
- PYTHON笔记
- Python笔记
- python笔记-------------
- python笔记
- Python笔记
- python 笔记
- Jzoj3898 树的连通性
- HDOJ2049
- UI自动化测试(二)浏览器操作及对元素的定位方法(xpath定位和css定位详解)
- 《MySQL入门很简单》学习笔记(2)之第2章Windows平台下安装与配置MySQL(关键词:数据库/MySQL/Windows)
- 线性表(二)
- < 笔记 > Python
- 网易2018校招内推编程题集合
- 【转】MongoDB基本命令使用
- 斐波那契堆是一系列具有最小堆序的有根树的集合
- python中的字符串的常见操作
- 内部类
- 【重点突破】——two.js模拟绘制太阳月亮地球转动
- Java多线程之synchronized
- Brandon的IT简史——AT&T(贝尔电话公司)