(XWZ)的python学习笔记Ⅳ——错误、调试和测试
目录
错误、调试和测试
错误处理
try...except...finally...
异常栈
抛出错误
调试
单元测试
错误、调试和测试
错误处理
try...except...finally...
- 在程序运行过程中,可能出现各种异常,比如整数除以零,值类型错误,从网络中抓取数据时网络突然中断等等,都可能导致程序无法再运行下去而中止,为此有必要提供一种机制能够及时捕获该异常进行处理使得程序能够继续运行下去。python中提供了try...except...finally...机制来进行处理,先看下面例子:
try: #测试代码段print('程序开始运行...')n = input('请输入一个数字:')res = 1024 / int(n)print('结果是:', res) except ValueError as e: #捕捉ValueError类型的错误print('错误是:', e) except ZeroDivisionError as e: #捕捉ZeroDivisionError类型的错误print('错误是:', e) else: #程序未出错时运行的代码段print('程序未出错!') finally: #程序最后运行的代码段print('程序运行结束!')
程序运行的结果如下:
程序开始运行...请输入一个数字:k 错误是: invalid literal for int() with base 10: 'k' 程序运行结束!
程序开始运行...请输入一个数字:0 错误是: division by zero 程序运行结束!
程序开始运行...请输入一个数字:512 结果是: 2.0 程序未出错! 程序运行结束!
该机制的结构是:代码测试代码块(try)——捕捉错误代码块(except)——最后运行的代码块(finally)。把有可能出错的代码段放入try代码块中,在该代码段中如果执行到某一句出现了异常,那么try代码段中剩余的语句就不会接着执行了(从上面前两个执行结果可以看出),解释器捕捉到该错误后转到相应的异常处理代码块(except)。若没有出现异常,那么就会执行else代码块。最后执行finally代码块(如果有finally代码块就一行会执行)。
这里要强调,错误也属于一种类,所有的错误均继承自
BaseException
类。在捕捉某一种错误时,其子类也一并“一网打尽”。比如:try:fun() except ValueError as e: print('错误是:', e) except UnicodeError as e:print('错误是:', e)
这里是ValueError的子类,故UnicodeError的错误也会由第一个except一并捕捉,从而第二个except捕捉不到错误。常见的错误类型及继承关系点这里查看。使用
try...except
捕获错误还有一个巨大的好处,就是可以跨越多层捕捉,比如,main()调用f1(),f1()调用f2(),在函数f2()中出现了错误,但我们只需在main()函数中捕捉到了就可以进行处理。
异常栈
- 如果程序中出现了错误,但我们没对对它进行捕捉,那么该错误就会一直向上抛,最终由解释器进行捕获并处理,但同时程序执行到这里也就结束了,所以最好能有我们自己捕获,这样捕捉到该错误后我们能够对它进行处理,同时程序还能够继续执行下去。下面来看如何利用异常栈来定位程序出错位置。
1 # -*- coding: utf-8 -*- 2 3 def f1(n): 4 print(int(n) / 1024, 'kb') 5 6 def f2(n): 7 f1(n) 8 9 def main(n): 10 f2(n) 11 12 main('l')
运行如下:
File "C:/Users/Whisky/.spyder-py3/temp.py", line 12, in <module>main('l')File "C:/Users/Whisky/.spyder-py3/temp.py", line 10, in mainf2(n)File "C:/Users/Whisky/.spyder-py3/temp.py", line 7, in f2f1(n)File "C:/Users/Whisky/.spyder-py3/temp.py", line 4, in f1print(int(n) / 1024, 'kb')ValueError: invalid literal for int() with base 10: 'l'
通过以上异常栈信息,就能够准确定位出出错的位置,首先在该模块中第12行main('l')这一句出错了,进一步往下看,在第10行main()中f2(n)这一句出错了,然而这不是最终原因,继续往下看是在第7行,f2函数中的f1(n)这一句错了,接着,最终原因是第4行f1函数中print(int(n) / 1024, 'kb')出错了,原因是ValueError: invalid literal for int() with base 10: 'l'
抛出错误
- 错误也是class,捕获一个错误就是捕获到该class的一个实例。在程序中也可以由我们自己抛出错误,需要使用关键字——raise:
def fun(i):if int(i) % 2:raise ValueError('%s是奇数' % i)def main():try:i = input('请输入一个偶数:')fun(i)print('正确!')except ValueError as e:print('错误是:', e)main()
运行结果如下
请输入一个偶数:6 正确!
请输入一个偶数:7 错误是: 7是奇数
- 我们也可以 定义自己的错误类,选择好继承的父类,然后就能在程序中使用raise抛出:
class MyError(ValueError):passdef main():try:raise MyError('抛出自定义的错误MyError!')except MyError as e:print(e)main()
运行结果:
抛出自定义的错误MyError!
我们在使用except捕获到错误后也可以再往上抛:
except ValueError as e:print(e)raise
raise语句在不带参数时是将错误e原样上抛,但我们也可以转换成另一种错误上抛:
def main():try:re = 10 / 0except ZeroDivisionError as e:raise ValueError('除数为零') main()
运行结果为:
Traceback (most recent call last):File "C:/Users/Whisky/.spyder-py3/temp.py", line 7, in <module>main()File "C:/Users/Whisky/.spyder-py3/temp.py", line 6, in mainraise ValueError('除数为零')ValueError: 除数为零
调试
- 一种最简单的方法就是使用print()函数直接打印出变量的值进行查看。
- 使用断言(assert):
s = input() i = int(s) assert i != 0, 'i的值为0' #在此处,我们断言i的值不为零,不然后面的程序就会出错 rs = 1024 / i print(rs)
若断言的语句不成功,就会抛出AssertionError错误:
File "C:/Users/Whisky/.spyder-py3/temp.py", line 4, in <module>assert i != 0, 'i的值为0'AssertionError: i的值为0
若使用python -O ×××.py运行python程序就会忽略代码中的断言,将其视为pass。
使用logging。logging一共有四种模式:DEBUG, INFO, WARNING, ERROR,优先级依次递增。如果将logging配置为INFO模式,那么可以这样使用:
import logging logging.basicConfig(level = logging.INFO)s = '0' n = int(s) logging.info('n = %d' % n) #打印出n的信息 print(10 / n)
除了可以在控制台输出信息外,还可以将信息输出到文件中。当指定level=INFO后logging.debug()就不起作用了,同理当指定level=WARNING后logging.info()和logging.debug()就不起作用了,指定level=ERROR后logging.debug(),logging.info()以及logging.warning()都不起作用了。
- 还可以使用pdb来对程序进行调试,我们需要导入pdb包,使用pdb.set_trace()可以给程序设置断点,当程序运行到端点时就会暂停,然后进入调试模式。在调试模式下,命令l是用来查看代码,命令n是执行下一条语句,命令p ×××(变量名)是查看变量,命令c是直接执行到下一个断点处,命令q是退出调试模式:
import pdbs1 = '1024' pdb.set_trace() s2 = '0' a = int(s1) b = int(s2) print(a / b)
> c:\users\whisky\.spyder-py3\temp.py(6)<module>()4 s1 = '1024'5 pdb.set_trace() ----> 6 s2 = '0'7 a = int(s1)8 b = int(s2)ipdb> l1 # -*- coding: utf-8 -*-2 import pdb3 4 s1 = '1024'5 pdb.set_trace() ----> 6 s2 = '0'7 a = int(s1)8 b = int(s2)9 print(a / b)10 11 ipdb> p s1 '1024'ipdb> n > c:\users\whisky\.spyder-py3\temp.py(7)<module>()5 pdb.set_trace()6 s2 = '0' ----> 7 a = int(s1)8 b = int(s2)9 print(a / b)ipdb> p s2 '0'ipdb> q Traceback (most recent call last):File "E:\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfileexec(compile(f.read(), filename, 'exec'), namespace)File "C:/Users/Whisky/.spyder-py3/temp.py", line 7, in <module>a = int(s1)File "C:/Users/Whisky/.spyder-py3/temp.py", line 7, in <module>a = int(s1)File "E:\Anaconda3\lib\bdb.py", line 88, in trace_dispatchreturn self.dispatch_line(frame)File "E:\Anaconda3\lib\bdb.py", line 113, in dispatch_lineif self.quitting: raise BdbQuitBdbQuit
- 最便捷高效的当然是使用IDE中的调试工具了,这里不做介绍。
单元测试
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。先定义一个简单的类Dog:
class Dog():def __init__(self, name, age):self.name = nameself.age = agedef get_age(self):if self.age > 30:raise ValueError()return self.age
接下来编写测试单元,需要导入unittest模块,我们选择继承于unittest.TestCase:
from test1 import Dog
import unittestclass TestA(unittest.TestCase):def test_init(self):d = Dog('Dolly', 10)self.assertEqual(d.name, 'Dolly')self.assertTrue(d.age < 30)def test_attr(self):d = Dog('Dolly', 10)d.name = 'Jacy'self.assertEqual(d.name, 'Jacy')self.assertTrue(isinstance(d.name, str))def test_attrerror(self):d = Dog('Dolly', 40)with self.assertRaises(AttributeError): #这里我们访问不存在的属性,所以期望抛出AttributeError错误val = d.colorwith self.assertRaises(ValueError): #这里我们期望能抛出ValueError错误d.get_age()
像test_init()这样以test开头的方法就是测试方法,不以test开头的方法便不会被认为是测试方法,在测试时就不会执行。对于每一类测试,我们都需要编写一个test_×××()方法。通过unittest.TestCase内置的测试就能够断言输出是否符合我们的期望,最常用的断言比如assertEqual()、assertTrue()、assertRaises()等等。
测试单元的运行通常有两种方法。第一种,在测试单元模块最后添加以下两行代码就能够将测试单元作为普通的脚本运行:
if __name__ == '__main__':unittest.main()
第二种,在命令行中输入python -m unittest ×××:
可以在单元测试中编写两个特殊的setUp()
和tearDown()
方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。
(XWZ)的python学习笔记Ⅳ——错误、调试和测试相关推荐
- error 系统错误 错误码10007_Python学习之错误调试和测试
Python学习之错误调试和测试 Python学习目录 在Mac下使用Python3 Python学习之数据类型 Python学习之函数 Python学习之高级特性 Python学习之函数式编程 Py ...
- Python学习笔记:Day 16 编写移动App
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day15 部署Web App
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day14 完成Web App
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day13 提升开发效率
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day 12 编写日志列表页
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此, 写下这些 ...
- Python学习笔记:Day11 编写日志创建页
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day 10 用户注册和登陆
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day 9 编写API
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
- Python学习笔记:Day 7 编写MVC
前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...
最新文章
- 越来越多BCH全节点客户端对BCH意味着什么?
- VSCode的连Linux远程开发碰到的坑解决
- border-radius 移动之伤
- 【每日算法Day 71】面试官想考我这道位运算题,结果我给出了三种解法
- 有助于提高锁性能的几点建议
- mysql字段加密存储过程_数据库:加密存储过程
- Java将多张图片合并保存到同一页PDF中
- 蚁景网络安全渗透测试工程师特训班学习记录
- npm run dev的实质
- pt100专用芯片_T100/PT1000温度传感器芯片-PT100温度传感器芯片
- CentOS 编译安装 Nebula Graph 3.10
- CSS运用中所体会到的方法
- 计算机不能关机处理方法,电脑无法关机的解决办法
- Keepalived之——*** WARNING - this build will not support IPVS with IPv6.解决方案
- 三年精进笃行,用友YonSuite“数智飞轮”高速运转起来了!
- java clh_Java多线程编程CLH锁详解
- HTTP网络连接相关知识整理(三):网络错误异常
- 目标检测中Regional Proposal到底是什么,RPN和Region Proposal、Proposals三者联系
- 回归问题-逐步回归(Stepwise Regression)
- arduino lora通讯_Arduino开发板和树莓派之间实现Lora点对点通讯
热门文章
- 第二十次CCF CSP认证考试经验
- openGL使用高度贴图模拟地球表面凹凸效果
- new Function的用法
- android4.4.3版本root,碉堡了!ROOT精灵支持Nexus 5等Android4.4.3机型ROOT
- 键盘鼠标录制哪个好用_美商海盗船Scimitar RGB Elite鼠标体验:再多技能也怕这把弯刀...
- recv 函数返回值说明
- C语言编写几何平均数的函数,Excel 计算几何平均值:GEOMEAN函数
- Roslyn 静态分析
- [转载]AutoCAD2013 以上利用AccoreConsole+ c# NetApi 批量处理图纸
- 高淇java_关于高淇JAVA中SORM总结学习笔记详细个人解释