3. 调试与测试
try except finally
执行逻辑:先运行try,遇到异常,则跳出try,如果except捕获异常,则执行except块,最后执行finnally(不管是否异常都会执行)
Python的错误其实也是class,所有的错误类型都继承自BaseException,except不仅会捕获指定类型的错误,还会捕获其所有子类错误。比如
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeError as e: #第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。
print('UnicodeError')
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
调试方法
assert, 用法 assert 表达式, 表达式为false时的输出, 运行py文件时加入-O选项可以屏蔽所有断言输出
log, 使用方法
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='myapp.log', filemode='w')#设置log等级,输出格式,输出文件名,默认是输出到屏幕
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
pdb
启动pdb: python3 -m pdb err.py
n:单步执行
l:查看当前代码
p 变量名:查看变量
q:退出调试
c:继续执行
代码中pdb.set_trace()设置断点
单元测试
步骤:
编写一个测试类,从unittest.TestCase继承
编写单元测试函数,以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
编写setUp()和tearDown()函数。这两个方法会分别在每调用一个测试方法的前后分别被执行。
setUp()和tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setUp()方法中连接数据库,在tearDown()方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码
运行单元测试,
方法1:在py文件中的最后运行unittest.main(),
方法2(推荐):python3 -m unittest mydict_test
import unittest
class 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')
if __name__ == '__main__':
unittest.main()
文档测试
python支持在注释中编写样例代码,然后自动测试注释中的代码。
应该是通过>>>来判断注释中的样例代码,然后会对比注释中的输出和测试的输出是否完全一致(就算是报错,报错信息也应该完全一样,一个字符都不差)。如果不完全一致,就会报错,如果完全一致,就什么都不输出。
# mydict2.py
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()