1.错误处理
try
![](https://img.haomeiwen.com/i14030079/ce9f85a68ba325d4.png)
![](https://img.haomeiwen.com/i14030079/9949a0313f7b5ada.png)
try内的代码一旦出错就会跳转到except语句块并且在出错代码处停止继续执行,然后在执行完except后,如果有finally语句块,则执行finally语句块。
那么如果try不出错那?
![](https://img.haomeiwen.com/i14030079/5bd2374b7b20ddf6.png)
![](https://img.haomeiwen.com/i14030079/e00ad7a5f4845b4c.png)
执行完try语句块后,不在执行except语句块的内容,但是还会执行finally语句块。
又因为错误有很多种,所以就会有多个except来捕获不同类型的错误。
![](https://img.haomeiwen.com/i14030079/83f2937f32c9820f.png)
![](https://img.haomeiwen.com/i14030079/54a90e56d510451e.png)
注意:因为错误类型也是类有继承关系,所以就有以下例子发生。
![](https://img.haomeiwen.com/i14030079/c7c1dbada48db3a7.png)
第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,如果有,也被第一个except给捕获了。
常见的错误类型和继承关系查看地址如下:
https://docs.python.org/3/library/exceptions.html#exception-hierarchy
跨越多层调用
比如函数main()调用foo(),foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了。
![](https://img.haomeiwen.com/i14030079/7f2a6796d13fc976.png)
调用栈
如果错误没有被捕获,就会入栈被捕获并且被打印出来。
![](https://img.haomeiwen.com/i14030079/2ad009319e13713e.png)
![](https://img.haomeiwen.com/i14030079/8bab18bb39fdbfd5.png)
我们由上往下看打印的错误信息。从20行的main()方法的执行开始追本溯源,按照逻辑最终找到了15行出的错误。
![](https://img.haomeiwen.com/i14030079/2dcbd3dc05735322.png)
注意:因此出错的时候一定要仔细推敲打印的错误信息
记录错误
利用Python内置的logging模块可以非常容易地记录错误信息并且打印完错误信息后会继续执行,最后正常退出。
![](https://img.haomeiwen.com/i14030079/7debcbd2ad0f95f1.png)
![](https://img.haomeiwen.com/i14030079/03cf3db35bf514b2.png)
通过配置,logging还可以把错误记录到日志文件里,方便事后排查。
自定义一个类接收抛出错误
![](https://img.haomeiwen.com/i14030079/afe65f37145380e5.png)
根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误。
![](https://img.haomeiwen.com/i14030079/9b8e2caf0d8790c2.png)
注意:尽量使用Python内置的错误类型。
raise语句
raise语句如果不带参数,就会把当前错误原样抛出。
![](https://img.haomeiwen.com/i14030079/c1a13c7b253943f1.png)
![](https://img.haomeiwen.com/i14030079/25b6c2f9276ce21b.png)
在打印一个ValueError!后,又把错误通过raise语句抛出去了的目的是:
捕获错误目的只是记录一下,便于后续追踪。
2.调试
第一种方法把可能有问题的变量打印出来,但是坏处是将来还得删掉它并且运行结果也会包含很多垃圾信息。
![](https://img.haomeiwen.com/i14030079/e56dc34ec738dc14.png)
![](https://img.haomeiwen.com/i14030079/76f45b13406c05e0.png)
第二种方法凡是用print()来辅助查看的地方,都可以用断言(assert)来替代:
(这里代码出了问题,例子之后补上。)
第三种方式是把print()替换为logging,和assert比,logging不会抛出错误,而且可以输出到文件。
![](https://img.haomeiwen.com/i14030079/b470d12c2814f56b.png)
![](https://img.haomeiwen.com/i14030079/2abdfe2aa7ee9e0f.png)
它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。
第四种方式是启动Python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。
![](https://img.haomeiwen.com/i14030079/3bf0e27913dcbd1d.png)
![](https://img.haomeiwen.com/i14030079/245a0d9064a2376e.png)
![](https://img.haomeiwen.com/i14030079/d12ed02065f4b0ca.png)
启动后,pdb定位到下一步要执行的代码并且在此行代码处会出现->符号。
l:查看代码
n:只执行一行的代码
p 变量名:查看变量
q:结束调试
第五种方式,这个方法也是用pdb,但是不需要单步执行,我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点。
![](https://img.haomeiwen.com/i14030079/b53a6c155afd3394.png)
![](https://img.haomeiwen.com/i14030079/dd66651eec5d2baf.png)
程序会自动在pdb.set_trace()暂停并进入pdb调试环境,命令c会继续运行。
第六种方式是一个支持调试功能的IDE。
注意:logging才是最好用的调试工具
3.单元测试
单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
4.文档测试
代码与其他说明可以写在注释中,然后,由一些工具来自动生成文档。
只要这些代码本身就可以直接运行,那么就可以自动执行写在注释中的这些代码。
这就是Python内置的“文档测试”(doctest)模块,他可以直接提取注释中的代码并执行测试。
通过'''来把“文档测试”(doctest)模块的内容包围起来即可。
doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用...表示中间一大段烦人的输出。
![](https://img.haomeiwen.com/i14030079/b69c2e126e75f220.png)
![](https://img.haomeiwen.com/i14030079/e1ebc00ffc61963f.png)
什么输出也没有。这说明我们编写的doctest运行都是正确的。
如果程序有问题的话,再运行就会报错!
当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。
网友评论