- 自学Python:编程基础、科学计算及数据分析
- 李金等
- 1707字
- 2020-11-28 22:26:25
2.5 异常与警告
异常和警告是编写程序过程中经常遇到的问题。为了更好地处理编程中遇到的问题,我们需要了解异常和警告的相关知识。
2.5.1 异常
1. 捕捉异常
我们在运行代码时经常遇到程序出错的情况,在Python中,这些错误通常叫做异常(Exception)。
例如,有这样一个用于计算以10为底的对数的程序,该程序使用raw_input()函数从命令行读取输入,计算它的对数并输出结果,直到我们输入为q为止:
乍看起来,程序似乎没甚么问题,然而,当我们输入一个负数时,程序抛出了一个ValueError异常,因为对数函数不能接受一个非正值输入:
正常情况下,Python程序在抛出异常后就会停止执行。如果不希望程序停止运行,可以使用一对关键字try和except来处理异常,其基本形式如下:
我们将可能抛出异常的代码,放入try块中,然后使用except块处理相应的异常。
当try块中的代码遇到异常时,这个异常会首先被传到except块。如果except块能处理这个异常,则执行except块相应的内容,然后程序继续执行;如果不能,该异常将被继续传递。
在上面的例子中,代码抛出的异常类型是ValueError,因此,我们改写程序,将可能出错的部分放入try块,并用关键字except处理ValueError类型的异常:
再执行这个程序时,输入负数或者0都不会中断程序,而是打印expect块输出的信息:
2. 处理不同类型的错误信息
我们对上面的代码进行修改,将y的值改为1/math.log10(x):
如果输入1:
因为1的对数为0,而1/0是一个非法操作,所以Python抛出了一个ZeroDivisionError类型的异常。
这个异常首先传到except块中,但我们定义的except块并不能处理这种类型的异常,因此,该异常被继续传递,程序停止运行。
这个问题有以下几种解决方式。
1)第一种方式,可以使用Exception替换ValueError,直接捕获所有的异常。Exception类型是各种异常的总称,所以ZeroDivisionError类型和ValueError类型都是一种特殊的Exception:
因此,下面的异常都会被except块处理:
2)第二种方式,我们可以在一个except块中声明多个异常类型:
程序运行抛出其中任意一种类型的异常都会被except块所处理。
3)第三种方式,通过多个except块分别处理各种类型的异常,每个except块负责处理一种类型的异常:
在这种情况下,两种类型的异常会被程序分别处理:
3. 得到异常的具体信息
当我们输入字符串“abcde”时,上面的程序会提示:“the value must be greater than 0”,这与实际情况不符。抛出ValueError异常的部分并不是math.log10()函数,而是float()函数。
调用float('abcde')时,由于所给字符串不能转化为浮点数,Python会抛出一个“ValueError: could not convert string to float: abcde”的异常。这个异常包含两部分的内容:前面的部分表示异常的类型,后面的部分表示异常的具体说明。
在except块中,我们可以这样获得异常的具体信息:
利用这种方式,我们首先将捕获到的异常保存在变量e中,并用属性.message查看相关的说明信息。
为了得到异常的具体信息,修改except块的部分:
运行后,当我们输入非法值时,就能得到异常的具体信息:
4. 抛出异常
在程序运行过程中,我们可以使用关键字raise抛出异常。
例如,当变量month为不合法的月份时抛出异常:
抛出的异常类型为ValueError,括号中为具体说明信息。
5. finally关键字
异常处理时,我们还可以加入一个以关键字finally开头的代码块,其作用为:不管try块中的代码是否抛出异常,finally块中的内容总是会被执行。
没有异常时,finally块会在try块的代码执行完毕后执行;出现异常时,finally块会在抛出异常前执行。因此,finally块可以用来作为程序抛出异常时的安全保证,比如确保打开的文件被正确关闭。
例如,一个没有异常的finally块:
如果异常被except块处理了,finally块在异常被处理后执行:
finally块的执行顺序总结如下:
● 没有异常,try块结束后执行;
● 异常抛出,except块没有处理异常,在抛出异常前执行;
● 异常抛出,except块处理了异常,在异常被处理后执行。
2.5.2 警告
在Python中,警告(Warning)通常用来告知用户某种做法是不好的,但这种做法不会影响程序的正常运行。
使用警告需要预先导入相关的模块:
In [1]: import warnings
然后调用warnings模块中的warn函数来抛出警告:
warn(msg, WarningType = UserWarning)
msg是警告的提示信息,WarningType参数用来指定警告的类型,如果不指定,默认的类型是UserWarning(用户警告):
In [2]: warnings.warn("test")
C:\Miniconda2\Scripts\ipython-script.py:1: UserWarning: test
常见的警告类型主要有:
● Warning,所有警告的父类,所有的警告都能看成一个Warning类;
● UserWarning,用户警告,warn函数的默认类型;
● DeprecationWarning,表示用户使用了未来会被废弃的功能;
● FutureWarning,表示用户使用了未来可能会改变的功能;
● RuntimeWarning,运行时警告。
有时候,我们在运行程序时不希望看见某种类型的警告,可以使用warnings模块中的filterwarnings来进行筛选:
在程序运行时,所有RuntimeWarning类型的警告都不会被显示。