错误类型
- 程序编写问题bug – 字符类型错误等
- 用户输入错误 – 输入不符合规定的字符串
- 异常,程序运行时无法预测 – 磁盘满了,无法写
错误处理
错误处理机制:try…except…finally…
try
运行可能会出错的代码,若出错则后续代码不再运行try
中存在错误代码时,执行except
语句块抛出异常finally
可有可无,不论是否异常,最后都会执行- 所有错误类型均继承自
BaseException
- 不同
except
可以对不同错误类型进行处理 except
可以捕获自身及子类的错误except
可以跨越多层调用
try:
print('try...')
test_int = 10 / int('a') # 除法运算错误
print('result = ', test_int) # 由于上一行代码错误,try的后续代码不再运行
except ZeroDivisionError as e:
print('except: ', e)
except ValueError as e:
print('ValueError:', e)
else:
print('no error was found!')
finally:
print('finally...')
print('END')
调用栈:出错时,须分析错误的调用栈信息,以定位错误的位置
Traceback (most recent call last):
……
……
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()
输出结果:
ERROR:root:division by zero
Traceback (most recent call last):
File "/Pratice/DEMO.py", line 8, in main
bar('0')
File "/Pratice/DEMO.py", line 5, in bar
return foo(s) * 2
File "/Pratice/DEMO.py", line 3, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
raise
抛出一个错误的实例
def foo(s):
n = int(s)
if n==0:
raise ValueError('invalid value: %s' % s)
return 10 / n
def bar():
try:
foo('0')
except ValueError as e:
print('ValueError!')
raise
bar()
输出结果:
Traceback (most recent call last):
ValueError!
File "/Pratice/DEMO1.py", line 14, in <module>
bar()
File "/Pratice/DEMO1.py", line 9, in bar
foo('0')
File "/Pratice/DEMO1.py", line 4, in foo
raise ValueError('invalid value: %s' % s)
ValueError: invalid value: 0
调试
使用print()调试,简单粗暴,但是调试过后需要删除调试代码
assert()
断言
def foo(s):
n = int(s)
assert n != 0, 'n is zero' # 若‘n != 0’不成立,则抛出AssertionError
return 10/s
def main():
foo('0')
main()
输出结果:
Traceback (most recent call last):
File "/Pratice/DEMO2.py", line 8, in <module>
main()
File "/Pratice/DEMO2.py", line 7, in main
foo('0')
File "/Pratice/DEMO2.py", line 3, in foo
assert n != 0, 'n is zero'
AssertionError: n is zero
tips:python -O DEMO2.py 可以将DEMO2.py中的assert当成pass来看
2. 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)
输出结果:
INFO:root:n = 0
Traceback (most recent call last):
File "/Pratice/DEMO3.py", line 7, in <module>
print(10 / n)
ZeroDivisionError: division by zero
pdb
调试器
让程序以单步方式运行,随时查看运行状态
➜ python -m pdb DEMO.py # 使用调试器查看单步运行状态
> /Users/amey/growingio/Pratice/DEMO.py(1)<module>()
-> import logging
(Pdb) l # l查看代码
1 -> import logging
2 logging.basicConfig(level=logging.INFO)
3
4 s = '0'
5 n = int(s)
6 logging.info('n = %d' % n)
7 print(10 / n)
[EOF]
(Pdb) n # n -> 单步执行代码
> /Users/amey/growingio/Pratice/DEMO.py(2)<module>()
-> logging.basicConfig(level=logging.INFO)
(Pdb) n # n -> 单步执行代码
> /Users/amey/growingio/Pratice/DEMO.py(4)<module>()
-> s = '0'
(Pdb) p s # p 变量名 -> 查看变量
> '0'
(Pdb) q # q -> 结束调试
单元测试unitcase
setUp()
和tearDown()
方法,在调用一个测试方法前后分别执行
[eg:连接关闭数据库]- 使用
python -m unittest test
可以批量运行多个单元测试
编写一个学生成绩单元测试
import unittest
class Student(object):
def __init__(self, name ,score):
self.name = name
self.score = score
def get_grade(self):
if(self.score > 100 or self.score < 0 or type(self.score) != int):
raise ValueError
elif(self.score < 60):
return 'C'
elif(self.score < 80):
return 'B'
else:
return 'A'
class TestStudent(unittest.TestCase):
def test_80_to_100(self):
s1 = Student('Amey', 100)
s2 = Student('Jimmy', 80)
self.assertEqual(s1.get_grade(),'A')
self.assertEqual(s2.get_grade(),'A')
def test_60_to_800(self):
s1 = Student('Bart', 79)
s2 = Student('Cindy', 60)
self.assertEqual(s1.get_grade(),'B')
self.assertEqual(s2.get_grade(),'B')
def test_0_to_60(self):
s1 = Student('Dan', 59)
s2 = Student('Lisa', 0)
self.assertEqual(s1.get_grade(),'C')
self.assertEqual(s2.get_grade(),'C')
def test_invaild(self):
s1 = Student('Jan', 101)
s2 = Student('King', -1)
with self.assertRaises(ValueError):
s1.get_grade()
with self.assertRaises(ValueError):
s2.get_grade()
if __name__ == '__main__':
unittest.main()
测试结果:
➜ python -m unittest DEMO4
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK
文档测试
doctest模块:可提取注视中的代码并执行测试
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def fact(n):
'''
计算 1*2*3*...*n
>>> fact(1)
1
>>> fact(-1)
Traceback (most recent call last):
File "/Pratice/demo.py", line 13, in <module>
print(fact(-1))
File "/Pratice/demo.py", line 7, in fact
raise ValueError
ValueError
>>> fact(10)
3628800
'''
if(n < 1):
raise ValueError
if(n == 1):
return 1
return n * fact(n-1)
if __name__ == '__main__':
import doctest
doctest.testmod()