什么是异常
本节开始介绍之前,先看看如下程序:
>>> print(a)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>
是不是很熟悉,这是我们前面经常看到的程序运行出现的错误。
作为Python
初学者,在学习Python
编程的过程中,经常会看到一些报错信息,使你编写的程序不能如期工作,如我们前面看到过的NameError
、SyntaxError
、TypeError
、ValueError
等,这些都是异常。
异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行。一般情况下,在Python
无法正常处理程序时就会发生异常。异常是Python
的对象,表示一个错误。当Python
脚本发生异常时,我们需要捕获并处理异常,否则程序会终止执行。
每一个异常都是一些类的实例,这些实例可以被引用,并且可以用很多种方法进行捕捉,使得错误可以被处理,而不是让整个程序失败。
异常处理
出现异常怎么办呢?
就如我们使用的工具出了点小毛病,我们可以想办法修理好它。程序也一样,前辈们经过不断积累与思考,创造了不少好方法处理程序中的异常,最简单的是使用try
语句处理。
try
语句的基本形式为try / except
。try / except
语句用来检测try
语句块中的错误,从而让except
语句捕获异常信息并处理。如果你不想在发生异常时结束程序,只需在try
语句块中捕获异常即可。
捕获异常的语法如下:
try:<语句> #运行别的代码
except <名字>:<语句> #如果在try部分引发了异常
try
的工作原理是,开始一个try
语句后,Python
就在当前程序的上下文中做标记,当出现异常时就可以回到做标记的地方。首先执行try
子句,接下来发生什么依赖于执行时是否出现异常。
如果try
后的语句执行时发生异常,程序就跳回try
并执行except
子句。异常处理完毕后,控制流就可以通过整个try
语句了(除非在处理异常时又引发新异常)。
例如以下示例所示(exp_exception.py):
def exp_exception(x, y):try:result = x / yprint('计算结果: ', result)except:print('程序出错: 除数不能为零')
程序执行结果如下:
程序出错: 除数不能为零
由执行结果看到,程序最后执行的是except
子句,如果语句正常,应该打印name
变量的值。
抛出异常
Python
使用raise
语句抛出一个指定异常。我们可以使用类(Exception的子类)
或实例参数调用raise
语句引发异常。使用类时程序会自动创建实例。
例如:
>>> raise Exception
Traceback (most recent call last):File "<stdin>", line 1, in <module>
Exception
>>> raise NameError('This is NameError')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
NameError: This is NameError
>>>
由操作结果看到,第一个示例raise Exception
引发了一个没有相关错误信息的普通异常,第二个示例输出了一些错误提示。
如果只想知道是否抛出了异常,并不想处理,使用一个简单的raise
语句就可以再次把异常抛出,例如:
try:raise NameError('This is NameError')
except NameError:print('An exception happened')# raise 不加reise 输出对应字符结束程序try:raise NameError('This is NameError') # 当前语句中的信息被输出
except NameError:print('An exception happened')# 添加raise则打印对应字符并再次显示异常raise
由输出结果看到,使用raise
可以输出更深层次的异常。在使用过程中,可以借助该方法得到更详尽的异常信息。
异常中的else
如果程序执行完异常还需要做其他事情,怎么办呢?
异常为我们提供了try…except…else
语句实现该功能,语法如下:
try:<语句> # 运行别的代码
except <名字>:<语句> # 如果在try部分引发了异常
else:<语句> # 如果没有发生异常
如果在try
子句执行时没有发生异常,就会执行else
语句后的语句(如果有else
)。使用else
子句比把所有语句都放在try
子句里面更好,这样可以避免一些意想不到而except
又没有捕获的异常。
例如:
def model_exception(x, y):try:a = x / yexcept:print('程序出现异常...')else:print('程序无异常则执行此语句...')model_exception(2, 1)
执行结果如下:
程序无异常则执行此语句...
由执行结果看到,没有发生异常时,会执行else
子句的流程。
综上所述,当程序没有发生异常时,通过添加一个else
子句做一些事情(比如输出一些信息)很有用,可以帮助我们更好地判断程序的执行情况。
自定义异常
尽管内建异常类包括大部分异常,而且可满足很多要求,但有时还是要创建自己的异常类。比如需要精确知道问题的根源,就需要使用自定义异常精确定位问题。可以通过创建一个新exception
类拥有自己的异常。异常应该继承自Exception
类,可以直接继承,也可以间接继承。
因为错误就是类,捕获一个错误就是捕获该类的一个实例,因此错误并不是凭空产生的,而是由一些不合理的部分导致的。Python
的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。如果要抛出错误,那么可以根据需要定义一个错误的类,选择好继承关系,然后用raise
语句抛出一个错误的实例。
例如(my_error.py):
class MyError(Exception):def __init__(self):passdef __str__(self):return 'this is self define error'def my_error_test():try:raise MyError()except MyError as e:print('exception info: ', e)my_error_test()
执行结果如下:
exception info: this is self define error
由程序和执行结果看到,程序正确执行了自定义的异常,并且需要继承Exception
类。
这只是一个简单的示例,还有不少细节需要琢磨,此处不做深入探讨,有兴趣的同学可以查阅相关资料进行实践。
**提示:**异常最好以Error
结尾,一方面贴近标准异常的命名,另一方面便于见名知意。
finally 子句
Python
中的finally
子句需要和try
子句一起使用,组成try / finally
的语句形式,try / finally
语句无论发生异常与否都将执行最后的代码。
例如(use_finally.py):
def use_finally(x, y):try:a = x / yfinally:print('No matter what happened, I will show in front of you')use_finally(2, 0)
执行结果为:
Traceback (most recent call last):File "/Users/poppies/Desktop/python_projects/基础部分/use_finally.py", line 8, in <module>use_finally(2, 0)File "/Users/poppies/Desktop/python_projects/基础部分/use_finally.py", line 3, in use_finallya = x / y
ZeroDivisionError: division by zero
No matter what happened, I will show in front of you
由执行结果看到,finally
子句被执行了,无论try
子句中是否发生异常,finally
都会被执行。
这里我们有一个疑问,虽然执行了finally
子句,但是最后还是抛出异常了,是否可以使用except
截获异常呢?
可以使用except
截获异常。try、except、else
和finally
可以组合使用,但要记得else
在except
之后,finally
在except
和else
之后。
对于上面的示例,可以更改如下(use_finally_1.py):
def use_finally(x, y):try:a = x / yexcept ZeroDivisionError:print('Some bad thing happened: division by zero')finally:print('No matter what happened, I will show in front of you')use_finally(2, 0)
执行结果如下:
Some bad thing happened: division by zero
No matter what happened, I will show in front of you
由执行结果看到,先执行了except
子句的输出语句,后面跟着执行了finally
子句的输出语句。如果再添加else
子句,当程序正常运行时会先执行else
子句,然后执行finally
子句。在有finally
的异常处理程序中,finally
中的子句一定是最后执行的。finally
子句在关闭文件或数据库连接时非常有用(文件操作和数据库操作后面会具体讲解)。
**提示:**在Python 2.5
之前的版本中,finally
需要独立使用,不能与try
语句配合。在Python 2.5
之后才支持这些语句的组合使用。
结语
以上就是关于python专题中的异常处理全部内容了,欢迎同学们在评论区讨论交流,有任何python开发、数据采集相关需求也可以后台或V加regentwan与我联系哟~