Python学习笔记(错误、调试和测试)
1、错误处理
使用try
Python内置了try...except...finally...的处理机制,用try来试运行代码,如果出错用except来捕获错误,最后如果有finally,就执行finally中的语句。
例子:
except如果什么都不写将会捕获所有错误。还可以写多个excpet来捕获不同的错误,如果没有错误发生还可以写else语句。
使用try...except的好处还有,可以只在主函数中捕获错误,当主函数调用的函数出错时,一样可以捕获到,而不用在所有函数中捕获。
调用栈
如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。
Traceback中从上到下,最下面的是错误的源头。
记录错误
我们可以记录错误信息,同时让程序继续运行下去,通过内置的logging模块来纪录错误信息。
程序打印完错误信息后还会继续运行,正常退出。
抛出错误
可以使用raise语句来抛出错误,使用raise时尽量使用python中内助的错误类型。
2、调试
断言
用于判断一个表达式,在表达式条件为 false 的时候触发异常。
assert expression等价于
if not expression:
raise AssertionError
assert 后面也可以跟参数assert expression [, arguments],等价于
if not expression:
raise AssertionError(arguments)
例子:
启动Python解释器时可以用-O参数来关闭assert。
logging
logging不会抛出错误,而且可以输出到文件:
默认情况下,logging模块将日志打印到屏幕上(stdout),日志级别为WARNING(即只有日志级别高于WARNING的日志信息才会输出),日志格式如下:
WARNING : root : warn message
日志级别 : Logger实例名称 : 日志消息内容
日志级别从低到高为:DEBUG、INFO、WARNING、ERROR、CRITICAL。
可以通过配置logging.basicConfig()来配置日志的显示级别和将日志输出到文件。
将日志等级改为INFO,输出到文件logger.log中,可以正常输出日志。
INFO:root:n = 0
3、单元测试
引入Pyhon自带的unittest模块,编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。setUp()、tearDown()会在每个测试用例(test开头)之前和之后执行。对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual():
待测试的类
测试用例:
运行测试单元可以在最后加上两行代码:
或者在运行脚本时加入-m unittest参数:
$ python -m unittest mydict_test
4、文档测试
写在文档注释中的代码可以提取并执行,使用doctest模块可以按照交互式命令行的输入和输出来判断测试结果是否正确。有测试异常的时候,可以用...标识中间一段追踪输出。
使用try
Python内置了try...except...finally...的处理机制,用try来试运行代码,如果出错用except来捕获错误,最后如果有finally,就执行finally中的语句。
例子:
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')
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')
调用栈
如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。
Traceback中从上到下,最下面的是错误的源头。
记录错误
我们可以记录错误信息,同时让程序继续运行下去,通过内置的logging模块来纪录错误信息。
# err_logging.py
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')
$ python3 err_logging.py
ERROR:root:division by zero
Traceback (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 zero
END
可以使用raise语句来抛出错误,使用raise时尽量使用python中内助的错误类型。
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')
断言
用于判断一个表达式,在表达式条件为 false 的时候触发异常。
assert expression等价于
if not expression:
raise AssertionError
assert 后面也可以跟参数assert expression [, arguments],等价于
if not expression:
raise AssertionError(arguments)
例子:
def foo(s):
n = int(s)
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
logging
logging不会抛出错误,而且可以输出到文件:
import logging
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
WARNING : root : warn message
日志级别 : Logger实例名称 : 日志消息内容
日志级别从低到高为:DEBUG、INFO、WARNING、ERROR、CRITICAL。
可以通过配置logging.basicConfig()来配置日志的显示级别和将日志输出到文件。
import logging
# 通过下面的方式进行简单配置输出方式与日志级别
logging.basicConfig(filename='logger.log', level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
INFO:root:n = 0
3、单元测试
引入Pyhon自带的unittest模块,编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。setUp()、tearDown()会在每个测试用例(test开头)之前和之后执行。对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual():
self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
下面是一个例子:待测试的类
class Count:
def __init__(self,a,b):
self.a = a
self.b = b
def add(self):
return self.a+self.b
import unittest
class TestDemo(unittest.TestCase):
def setUp(self):
print("setUp")
def test_add(self):
z = Count(2,3)
self.assertEqual(z.add(),5)
def test_invid_add(self):
z = Count(2, 3)
self.assertNotEqual(z.add(),6)
def tearDown(self):
print("tearDown")
if __name__=="__main__":#把测试脚本当成正常的脚本运行
unittest.main()
if __name__=="__main__":#把测试脚本当成正常的脚本运行
unittest.main()
$ python -m unittest mydict_test
4、文档测试
写在文档注释中的代码可以提取并执行,使用doctest模块可以按照交互式命令行的输入和输出来判断测试结果是否正确。有测试异常的时候,可以用...标识中间一段追踪输出。
# 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()
评论
发表评论