异常处理
1. 异常的定义
异常就是一个事件, 它影响了一个程序的正常运行,也可以理解为,程序运行到了一个不能处理的问题,然后产生的一个错误。
在python
中异常相关的关键字:try、except、else、finally、raise
2. 异常引发
当程序出现错误的时候,系统会自动引发异常,当然我们也可以允许程序自己引发异常,通过raise
语句来抛出异常。
可以自己根据业务需求来抛出异常,例如程序中的数据、执行与既定的业务需求不符,这些异常系统无法自动抛出,需要我们根据需求来进行异常的抛出。
raise
语句的使用方法:
- 单独一个
raise
,可以引发当前上下文中捕获的异常,若上下文中无异常,则会引发RuntimeError
。 raise
异常类,该句将引发指定异常类的默认实例。raise
异常对象,该句将引发指定的异常对象。
使用assert
关键字引发异常:
l = [1, 2, 3, 4]
assert len(l) < 3, "列表长度超过3"
print("正常")
#======output=====
Traceback (most recent call last):
File "F:/.../demo.py", line 3, in <module>
assert len(l) < 3, "列表长度超过3"
AssertionError: 列表长度超过3
上述代码等价于:
l = [1, 2, 3, 4]
if len(l) > 3:
raise AssertionError("列表长度超过3")
print("正常")
3. 异常处理
3.1 try…except捕获异常
try:
# 业务处理代码
except Exception:
# 对异常进行的处理
对异常进行处理后,代码还可以继续执行,如果不捕获异常,代码将直接结束运行。
try:
l = []
print(l[1])
except Exception:
print("捕获了一个异常")
print("继续执行")
#======output======
捕获了一个异常
继续执行
有时候,我们需要对不同类型的异常进行不同的异常处理,python
中可以通过使用多个except
语句来进行不同类型的异常的捕获与处理。
try:
l = []
# int('fjdk') # 将这一行注释去掉,将会引发ValueError,被第二个Except块捕获
print(l[1])
except IndexError:
print("捕获了一个IndexError异常")
except ValueError:
print("捕获了一个ValueError异常")
except Exception:
print("捕获了其它异常")
通常在最后的except
块中要捕获其它所有的异常,对其它异常进行统一处理,以保证程序能够顺利运行。
如果异常已经被前面的except
块捕获,进入异常处理,后面的except
块将不再执行。
当然我们也可以对一部分异常进行统一的处理,方式如下:
try:
l = []
int('fjdk')
# print(l[1])
except (IndexError, ValueError): # 对多个不同的异常进行统一的处理
print("捕获了一个IndexError异常或ValueError异常")
except Exception:
print("捕获了其它异常")
3.2 try…except…else捕获异常
与上面的try...except
语句相同,只是添加了一个else
语句,在没有异常的情况下,else
块中的代码将会被执行。
try:
l = ['1', '2']
print(l[1])
except (IndexError, ValueError):
print("捕获了一个IndexError异常或ValueError异常")
except Exception:
print("捕获了其它异常")
else:
print("没有任何异常")
#=====output======
2
没有任何异常
3.3 try…except…finally捕获异常
在该结构中,无论try
代码块中的代码是否正常执行,finally
子句中的代码块总会被执行。在开发过程中通常用来释放资源。
下面是运行出现异常的例子:
l = [1, 2, 3]
try:
print(l[5])
print("没有出现异常")
except Exception as e:
print("出现异常!")
finally:
print("运行到finally")
#======output======
出现异常!
运行到finally
代码中无异常的例子:
l = [1, 2, 3]
try:
print(l[1])
print("没有出现异常")
except Exception as e:
print("出现异常!")
finally:
print("运行到finally")
#=======output=====
2
没有出现异常
运行到finally
在函数中如果使用finally
要注意一些问题,应尽量避免在finally
块中使用return
语句、raise
语句等。例如在finally
语句中使用了return
语句,将会出现以下情况:
def test():
try:
return True
finally:
return False
print(test())
#======output====
False
上述代码也就是不管怎么写,test
函数的返回值都是False
。因为不管try
语句块中的代码是否执行,finally
块中的语句都要执行,所以函数的返回值永远是False
。
4. 访问异常信息
4.1 异常对象访问异常信息
通过异常对象来访问异常信息:
- args:返回异常的错误编号和错误信息
- with_traceback():用于处理异常的传播轨迹,查看异常的传播轨迹可追踪异常触发的源头
import sys
try:
f = open('test.txt')
print("没有出现异常")
except Exception as e:
print(e.args) # 访问异常的错误信息
print(e.with_traceback(sys.exc_info()[2])) #用于处理异常的传播轨迹,查看异常的传播轨迹可追踪异常触发的源头,也可看到异常一路触发的轨迹。
print("出现异常!")
finally:
print("运行到finally")
#=======output=======
(2, 'No such file or directory')
[Errno 2] No such file or directory: 'test.txt'
出现异常!
运行到finally
sys.exec_info()
如果整个堆栈中都没有正在处理的异常,则返回三个
None
的元组;否则,返回值为(type, value, traceback)
。其中
type
表示正在处理的异常类型;value
表示异常实例;traceback
表示一个回溯对象,该对象封装了最初发生异常时的调用堆栈。
4.2 使用traceback
模块访问异常
该模块提供了一个标准接口来提取、格式化和打印 Python 程序的堆栈跟踪结果。
-
print_tb()
:要传入traceback
对象,可以从sys.exec_info()
中获取。可以设置打印的异常的追溯限制条数,通过limit
参数设置。 -
print_exception()
:要传入etype,value,tb
三个参数,正好对应sys.exec_info()
函数返回的三个参数。同样也可以设置limit
参数,另外还可以通过file
参数指定输出信息的位置,可以输出到控制台,也可以输出到文件。 -
print_exc()
:是print_exception()
函数的简化。 -
format_exc()
:格式化堆栈跟踪和异常信息,返回的是一个字符串。
import sys
import traceback
def func():
return 2 / 0
def test():
print("这是test函数")
func()
try:
test()
print("没有出现异常")
except Exception as e:
traceback.print_tb(sys.exc_info()[2], limit=1)
# traceback.print_exception(*sys.exc_info(), limit=2)
# traceback.print_exc(limit=2)
print("出现异常!")
finally:
print("运行到finally")
#======output====
这是test函数
出现异常!
运行到finally
File "F:/.../demo.py", line 9, in <module>
test()
#如果使用print_exception函数,打印结果如下:(使用print_exc函数打印结果相同)
这是test函数
出现异常!
运行到finally
Traceback (most recent call last):
File "F:/.../demo.py", line 9, in <module>
test()
File "F:/.../demo.py", line 7, in test
func()
ZeroDivisionError: division by zero
5. 自定义异常
自定义的异常必须继承Exception
基类或者Exception
的子类,自定义异常类时不需要实现过多的方法,根据自己的需求实现一下__init__()
方法和__str__()
方法即可。
l = [1, 2, 3, 4]
class ListTooLongError(Exception):
def __init__(self, len_list):
self.len_list = len_list
def __str__(self):
return "The length of list is {} which is too long.".format(self.len_list)
if len(l) > 3:
raise ListTooLongError(len(l))
else:
print("没有异常")