前言

最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖子,廖雪峰的课程连接在这里:廖雪峰
Python的相关介绍,以及它的历史故事和运行机制,可以参见这篇:python介绍
Python的安装可以参见这篇:Python安装
Python的运行模式以及输入输出可以参见这篇:Python IO
Python的基础概念介绍,可以参见这篇:Python 基础
Python字符串和编码的介绍,可以参见这篇:Python字符串与编码
Python基本数据结构:list和tuple介绍,可以参见这篇:Python list和tuple
Python控制语句介绍:ifelse,可以参见这篇:Python 条件判断
Python控制语句介绍:循环实现,可以参见这篇:Python循环语句
Python数据结构:dict和set介绍Python数据结构dict和set
Python函数相关:Python函数
Python高阶特性:Python高级特性
Python高阶函数:Python高阶函数
Python匿名函数:Python匿名函数
Python装饰器:Python装饰器
Python偏函数:Python偏函数
Python模块:Python模块
Python面向对象编程(1):Python面向对象
Python面向对象编程(2):Python面向对象(2)
Python面向对象编程(3):Python面向对象(3)
Python面向对象编程(4):Pyhton面向对象(4)
Python面向对象高级编程(上):Python面向对象高级编程(上)
Python面向对象高级编程(中上):Python面向对象高级编程(中上)
Python面向对象高级编程(中下):Python面向对象高级编程(中下)
Python面向对象高级编程(完):Python面向对象高级编程(完)
目录:

  • 前言
  • 错误、调试和测试
  • 错误处理
    • try
    • 调用栈
    • 抛出错误
  • err_reraise.py

错误、调试和测试

在程序运行过程中,总会遇到各种各样的错误。
有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的。
有的错误是用户输入造成的,比如让用户输入email地址,结果得到一个空字符串,这种错误可以通过检查用户输入来做相应的处理。
还有一类错误是完全无法在程序运行过程中预测的,比如写入文件的时候,磁盘满了,写不进去了,或者从网络抓取数据,网络突然断掉了。这类错误也称为异常,在程序中通常是必须处理的,否则,程序会因为各种问题终止并退出。
Python内置了一套异常处理机制,来帮助我们进行错误处理。
此外,我们也需要跟踪程序的执行,查看变量的值是否正确,这个过程称为调试。Python的pdb可以让我们以单步方式执行代码。
最后,编写测试也很重要。有了良好的测试,就可以在程序修改后反复运行,确保程序输出符合我们编写的测试

错误处理

在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。在操作系统提供的调用中,返回错误码非常常见。比如打开文件的函数open(),成功时返回文件描述符(就是一个整数),出错时返回-1。
用错误码来表示是否出错十分不便,因为函数本身应该返回的正常结果和错误码混在一起,造成调用者必须用大量的代码来判断是否出错:

def foo():r = some_function()if r==(-1):return (-1)# do somethingreturn rdef bar():r = foo()if r==(-1):print('Error')else:pass

一旦出错,还要一级一级上报,直到某个函数可以处理该错误(比如,给用户输出一个错误信息)。
所以高级语言通常都内置了一套try…except…finally…的错误处理机制,Python也不例外。

try

让我们用一个例子来看看try的机制:

try:print('try...')r = 10 / 0print('result:', r)
except ZeroDivisionError as e:print('except:', e)
finally:print('finally you die')
print('END')

当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。

上面的代码在计算10 / 0时会产生一个除法运算错误:

try...
except: division by zero
finally you die
END

从输出可以看到,当错误发生时,后续语句print(‘result:’, r)不会被执行,except由于捕获到ZeroDivisionError,因此被执行。最后,finally语句被执行。然后,程序继续按照流程往下走。

如果把除数0改成2,则执行结果如下:

try...
result: 5
finally...
END

由于没有错误发生,所以except语句块不会被执行,但是finally如果有,则一定会被执行(可以没有finally语句)

你还可以猜测,错误应该有很多种类,如果发生了不同类型的错误,应该由不同的except语句块处理。没错,可以有多个except来捕获不同类型的错误:

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')

int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError。

此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

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的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。比如:

try:foo()
except ValueError as e:print('ValueError')
except UnicodeError as e:print('UnicodeError')

第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。
Python所有的错误都是从BaseException类派生的,常见的错误类型和继承关系看这里:常见错误
使用try…except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理:

def foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():try:bar('0')except Exception as e:print('Error:', e)finally:print('finally...')

也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try…except…finally的麻烦。

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来看看err.py:

# err.py:
def foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():bar('0')main()

执行,结果如下:

$ python3 err.py
Traceback (most recent call last):File "err.py", line 11, in <module>main()File "err.py", line 9, in mainbar('0')File "err.py", line 6, in barreturn foo(s) * 2File "err.py", line 3, in fooreturn 10 / int(s)
ZeroDivisionError: division by zero

出错并不可怕,可怕的是不知道哪里出错了。解读错误信息是定位错误的关键。我们从上往下可以看到整个错误的调用函数链:

错误信息第1行:Traceback (most recent call last):告诉我们这是错误的跟踪信息。第2~3行:File "err.py", line 11, in <module>main()调用main()出错了,在代码文件err.py的第11行代码,但原因是第9行:File "err.py", line 9, in mainbar('0')调用bar('0')出错了,在代码文件err.py的第9行代码,但原因是第6行:File "err.py", line 6, in barreturn foo(s) * 2原因是return foo(s) * 2这个语句出错了,但这还不是最终原因,继续往下看:File "err.py", line 3, in fooreturn 10 / int(s)原因是return 10 / int(s)这个语句出错了,这是错误产生的源头,因为下面打印了:ZeroDivisionError: integer division or modulo by zero

根据错误类型ZeroDivisionError,我们判断,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。
出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置。

记录错误

如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

Python内置的logging模块可以非常容易地记录错误信息:

# err_logging.pyimport loggingdef foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():try:bar('0')except Exception as e:logging.exception(e)main()
print('END')

同样是出错,但程序打印完错误信息后会继续执行,并正常退出:

ERROR:root:division by zero
Traceback (most recent call last):File "E:/python/example/example_test2.py", line 13, in mainbar('0')File "E:/python/example/example_test2.py", line 9, in barreturn foo(s) * 2File "E:/python/example/example_test2.py", line 6, in fooreturn 10 / int(s)
ZeroDivisionError: division by zero
END

通过配置,logging还可以把错误记录到日志文件里,方便事后排查。

抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。
如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

# err_raise.py
class FooError(ValueError):passdef foo(s):n = int(s)if n==0:raise FooError('invalid value: %s' % s)return 10 / nfoo('0')

执行,可以最后跟踪到我们自己定义的错误:

Traceback (most recent call last):
File “E:/python/example/example_test3.py”, line 11, in
foo(‘0’)
File “E:/python/example/example_test3.py”, line 8, in foo
raise FooError(‘invalid value: %s’ % s)
FooError: invalid value: 0


只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。最后,我们来看另一种错误处理的方式:

err_reraise.py

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()


在bar()函数中,我们明明已经捕获了错误,但是,打印一个ValueError!后,又把错误通过raise语句抛出去了,这不有病么?其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。好比一个员工处理不了一个问题时,就把问题抛给他的老板,如果他的老板也处理不了,就一直往上抛,最终会抛给CEO去处理。raise语句如果不带参数,就会把当前错误原样抛出。此外,在except中raise一个Error,还可以把一种类型的错误转化成另一种类型:

try:
10 / 0
except ZeroDivisionError:
raise ValueError(‘input error!’)
“`

只要是合理的转换逻辑就可以,但是,决不应该把一个IOError转换成毫不相干的ValueError

Python学习笔记:错误,测试,调试(起)相关推荐

  1. Python学习笔记:Day11 编写日志创建页

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  2. Python学习笔记:Day 9 编写API

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  3. Python学习笔记:Day5 编写web框架

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  4. Python学习笔记:web开发2

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  5. Python学习笔记:访问数据库

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  6. Python学习笔记:网络编程

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  7. OpenCV之Python学习笔记

    RSS订阅 登陆 注册 原文链接地址:http://www.itozi.net/19477.html OpenCV之Python学习笔记 ITOZI 发布于 2015-08-06 分类:OpenSta ...

  8. Python学习笔记:第四站 往哪走

    Python学习笔记 文章目录 Python学习笔记 第四站 往哪走 1. 程序的组织结构 2. 顺序结构 3. 对象的布尔值 4. 分支结构 5. pass空语句 6. 本章作业 课程笔记参考B站视 ...

  9. Python学习笔记13_模块

    Python学习笔记13_模块 文章目录 Python学习笔记13_模块 1.导入模块和的方法及使用 2.分层的文件系统中常用的包结构 3.OS 模块 4.sys 模块 5.math 模块 6.ran ...

  10. 【Python学习笔记】b站@同济子豪兄 用pytorch搭建全连接神经网络,对Fashion-MNIST数据集中的时尚物品进行分类

    [Python学习笔记]原作b站@同济子豪兄 用pytorch搭建全连接神经网络,对Fashion-MNIST数据集中的时尚物品进行分类 跟着b站@同济子豪兄的视频自学写的代码,内容是用pytorch ...

最新文章

  1. 初识Memcached
  2. MF RC522读卡芯片手册
  3. 解决media player内部应用程序错误
  4. webpack 3.1 升级webpack 4.0
  5. 【BZOJ3831】Little Bird,单调队列优化DP
  6. win7系统搭建tftp服务器,Win7旗舰版如何开启TFTP服务器|开启Win7旗舰版TFTP服务器的方法...
  7. 两种方案的demo示例
  8. java反射 一些理解
  9. 人人都可以用Mac--安装和卸载应用软件
  10. java map 遍历取值_遍历 MAP 集合取值方式
  11. 印象笔记三级目录_如何建立印象笔记的三层目录构架
  12. win10 软路由_千元完美的家用低功耗软路由:J4125 迷你电脑GK41开箱体验!又是播放器,也是服务型AIO!...
  13. 【实习周报】2019年6月 前端开发实习工作周报汇总
  14. 在mysql中,涉及到金钱的数据类型一般是什么?
  15. 你中了微软的圈套么?
  16. java mvp模式_什么是mvp开发模式?(下面就对Android中MVP做一些阐述)
  17. 网络安全(数据库等)
  18. java计算机毕业设计追星网站源码+数据库+系统+lw文档
  19. Unity学习笔记:Unity 3D 飞机大战
  20. 13 款炫酷的 MySQL 可视化管理工具!好用到爆!!

热门文章

  1. just have a view of the open source project i contributed!!!
  2. vsftp实现只能上传不能下载、删除权限配置
  3. 在Linux操作系统下使用虚拟光驱的方法
  4. Web前端必备-Nginx知识汇总
  5. 爬虫_微信小程序社区教程(crawlspider)
  6. 路由系统(urls.py)
  7. 深入浅出面向对象和原型【番外篇——重新认识new】
  8. 深入了解 Oracle Flex ASM 及其优点
  9. 算法题:找出整数数组中两个只出现一次的数字
  10. openerp 禁止导出