错误、异常和程序调试
语法错误
- 拼写错误
- 脚本程序不符合Python的语法规范
- 缩进错误
异常的处理
异常处理的基本语法
Python中使用try语句来处理异常,和Python中其他语句一样,try语 句也要使用缩进结构,try语句也有一个可选的else语句块。一般的try语 句基本形式如下。
try:
<语句(块)> #可能产生异常的语句(块)
except <异常名1>: #要处理的异常
<语句(块)> #异常处理语句
except <异常名2>: #要处理的异常
<语句(块)> #异常处理语句
else:
<语句(块)> #未触发异常,则执行该语句(块)
finally:
<语句(块)> #始终执行该语,一般为了达到释放资源等目的
注:else语句块在未引发异常情况下得到运行。
Python主要的内置异常及其处理
在Python中常见的异常都已经预定义好了,在交互式环境中,用 dir(__builtins__)命令,就会显示出所有的预定义异常。
异常名 | 描述 |
AttributeError | 调用不存在的方法引发的异常 |
EOFError | 遇到文件末尾引发的异常 |
ImportError | 导入模块出错引发的异常 |
IndexError | 列表越界引发的异常 |
IOError | I/O操作引发的异常,如打开文件出错等 |
KeyError | 使用字典中不存在的关键字引发的异常 |
NameError | 使用不存在的变量名引发的异常 |
TabError | 语句块缩进不正确引发的异常 |
ValueError | 搜索列表中不存在的值引发的异常 |
ZeroDivisionError | 除数为零引发的异常 |
except语句主要有以下几种用法。
- except:#捕获所有异常;
- except <异常名>:#捕获指定异常;
- except (异常名1,异常名2):#捕获异常名1或者异常名2;
- except <异常名> as <数据>:#捕获指定异常及其附加的数据;
- except(异常名1,异常名2)as <数据>:#捕获异常名1或者异常名 2及异常的附加数据。
手工抛出异常
用raise手工抛出异常
使用raise引发异常十分简单,raise有以下几种使用方式。
- raise 异常名
- raise 异常名,附加数据
- raise 类名
assert语句
assert语句的一般形式如下。
- assert <条件测试>, <异常附加数据> #其中异常附加数据是可选的
assert语句是简化的raise语句,它引发异常的前提是其后面的条件测 试为假。
自定义异常类
在Python中定义异常类不用从基础完全自己定义,只要通过继承 Exception类来创建自己的异常类。异常类的定义和其他类没有区别,最 简单的自定义异常类甚至可以只继承Exception类,类体为pass如:
class MyError (Exception): #继承Exception类
pass
如果需要异常类带有一定的提示信息,也可以重载__init__和 __str__这两个方法。
用pdb调试程序
Python解释器可以发现程序中的语法错误,在试运行时会中断执行 并给出提示。但是程序中逻辑上的错误,或其他非语法错误不会被发 现。虽然程序能够正常运行,但是运行后得不到预想的结果,这就要对 程序进行调试。
调试程序可以使用Python自带的pdb模块,其功能有设置断点、单 步执行、查看变量等。它可以用命令行参数的形式启动,也可以通过导 入模块使用。
调试语句块函数
pdb模块中的调试语句块的函数及参数原型为:
run( statement[, globals[, locals]])
- statement 要调试的语句块,以字符串的形式表示;
- globals 可选参数,设置statement运行的全局环境变量;
- locals 可选参数,设置statement运行的局部环境变量。
完整命令 | 简写命令 | 描述 |
args | a | 打印当前函数的参数 |
clear | cl | 清除断点 |
break | b | 设置断点 |
condition | 无 | 设置条件断点 |
continue | c或者cont | 继续运行,指导遇到断点或者程序结束 |
disable | 无 | 禁止断点 |
enable | 无 | 启用断点 |
help | h | 查看pdb帮助 |
ignore | 无 | 忽略断点 |
jump | j | 跳转到制定行数运行 |
list | l | 列出程序清单 |
next | n | 执行下条语句,遇到函数不进入其内部 |
p | p | 打印变量值,也可以用print |
quit | q | 退出pdb |
return | r | 一直运行到函数返回 |
tbreak | 无 | 设置临时断点,断点只中断一次 |
step | s | 执行下一条语句,遇到函数进入其内部 |
where | w | 查看所在的位置 |
! | 无 | 在pdb中执行语句 |
<string>(3)<module>()则表示即将执行代码语句行数和所在模块 为匿名模块
调试函数
pdb模块中的调试函数应当调用模块中的runcall函数,其参数原型为:
runcall( function[, argument,...])
- function 函数名;
- argument 函数的参数。
测试程序
当编写完程序,并排除了语法错误之后,虽然程序可以运行,但程 序的运行结果和期待的可能也会不一致。这说明程序中可能会有bug, 即程序的逻辑错误。发现和清除这类错误就要对程序进行测试,最好的 方法就是使用测试驱动的开发(TDD)。对程序进行测试种类包括可用 性测试、功能测试、单元测试及整合测试等。
用testmod函数测试
用testmod函数进行单元测试,就要将测试用例写入程序的docstring 中,然后可以用两种方法进行测试。
【实例7-12】演示了使用doctest模块的testmod函数进行基本 的单元测试,代码如下
import pdb
def grade (sum):
"""
>>> grade (100)
'优秀'
>>> grade (80)
'良'
>>> grade (65)
'合格'
>>> grade (10)
'不合格'
"""
if sum > 90:
return '优秀'
if sum > 80:
return '良'
if sum > 60:
return '合格'
if sum < 60:
return '不合格'
if name =='__main__':
import doctest
doctest.testmod()
【代码说明】代码中定义了一个根据考试分数返回考试评价的函 数,并在其中的docsting中加入了测试用例,其中形如“>>> grade(100)”就是一个测试用例,并在下一行写出期待返回的结果。程 序中共写入4个测试用例。
注:>>> grade(100)语句中>>>后要有一个空格
【运行效果】如图7.14所示,测试结果信息中,共运行了4个测试 用例,有一个测试失败,并且指出了哪个测试失败,测试期待返回值和 真实返回值。
这种写法就是当单独运行这个程序时,就会对其进行测试。如果不 希望这样,还可以通过在命令行下运行以下命令进行测试:
python -m doctest 7-14.py
用testfile函数测试
如果因为某种原因,你不想或不能将测试用例写入程序文件中, 就可以应用testfile函数进行测试。
【实例7-13】演示了使用doctest模块的testfile函数进行基本的 单元测试,代码如下:
import pdb
def grade (sum):
if sum > 90:
return '优秀'
if sum > 80:
return '良'
if sum > 60:
return '合格'
if sum < 60:
return '不合格'
将测试用例写入一个mytest.txt文件之中,内容如下:
from test import grade #将上面程序文件存入test.py文件中
>>> grade (100)
'优秀'
>>> grade (80)
'良'
>>> grade (65)
'合格'
>>> grade (10)
'不合格'
【代码说明】代码中定义了一个根据考试分数返回考试评价的函 数。并在mytest.txt文件中写入了4个测试用例。如果在交互模式下运行,可使用以下程序命令:
import doctest doctest.testfile('mytest.txt')
如果在命令行模式下运行测试,可使用命令:
python -m doctest mytest.txt