错误处理
try...except...finally...
的错误处理机制。
try
# 可以有多个except来捕获不同类型的错误
# 没有错误发生,可以在except语句块后面加一个else
# 捕获该类型的错误及其所有子类
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')
- 所有的错误都是从
BaseException
类派生。 try...except
可以跨越多层调用。
调用栈
- 如果错误没有被捕获,会一直往上抛,最后被解释器捕获,打印错误信息,程序退出。
- 分析错误调用栈信息,能定位错误位置。
记录错误
- 内置
logging
模块可记录错误信息,打印完错误信息后会继续执行,并正常退出。
import logging
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
logging.exception(e)
main()
print('END')
抛出错误
- 错误是class,捕获一个错误就是捕获一个实例。
- 根据需要定义一个错误的class,选择好继承关系,用
raise
语句抛出一个错误的实例。 - 捕获错误,打印错误内容后,又把错误通过
raise
语句抛出,让顶层调用者去处理。 raise
不带参数——当前错误原样抛出。- 在
except
中raise
一个Error,可把错误类型转化成另一种类型。
调试
- 用
print()
把可能有问题的变量打印出来看看,运行结果会包含很多垃圾信息。
断言
- 用
print()
辅助查看地方,都可用断言(assert)来替代。
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
- 断言失败,
assert
语句会抛出AssertionError。
- 用
-O
参数来关闭assert
,
关闭后,所有的assert
语句当成pass
。
logging
print()
替换为logging
,和assert
比,logging
不会抛出错误,且可输出到文件。
import logging
# 允许指定记录信息的级别,有debug,info,warning,error等几个级别
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
pdb
pdb.set_trace()
- 不需要单步执行,
import pdb
后,可能出错地方放pdb.set_trace()
,即设置一个断点。
IDE(Integrated Development Environment )
单元测试
- 对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
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
# 编写单元测试,需要引入Python自带的unittest模块
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
# 以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行
# unittest.TestCase提供了很多内置的条件判断,只需要调用这些方法就可以断言输出是否是期望的。
# 最常用的断言就是assertEqual()
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()
# 期待抛出指定类型的Error,比如通过d['empty']访问不存在的key时,断言会抛出KeyError
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
# 通过d.empty访问不存在的key时,我们期待抛出AttributeError
with self.assertRaises(AttributeError):
value = d.empty
运行单元测试
if __name__ == '__main__':
unittest.main()
setUp与tearDown
- 编写两个特殊的
setUp()
和tearDown()
方法,会分别在每调用一个测试方法的前后被执行。
文档测试
def abs(n):
'''
Function to get absolute value of number.
Example:
>>> abs(1)
1
>>> abs(-1)
1
>>> abs(0)
0
'''
return n if n >= 0 else (-n)
- 内置“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。
- 当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。