异常基础
在python代码中捕获异常,可以使用try/except
语句。它的基本形式如下:
try:
# 需要检查的代码
except Exception as e:
# 处理异常的代码
还可以使用finally子句,在异常发生时执行一些清理工作,以及不管是否发生异常都要执行的操作。
try:
# 需要检查的代码
except Exception as e:
# 处理异常的代码
finally:
# 不管是否发生异常都要执行的代码
此外,在except
子句中,可以根据不同的异常类型使用不同的处理方式,以便更加精确地处理异常。
try:
# 需要检查的代码
except ValueError as e:
# 处理ValueError异常的代码
except TypeError as e:
# 处理TypeError异常的代码
except Exception as e:
# 处理其他异常的代码
可以发现,为了给一个方法添加异常处理,需要在方法中添加大量的try/except
语句,这样会使代码变得很冗长,不易阅读。因此,笔者尝试一种更加优雅的方式来处理异常。
异常处理装饰器
笔者的初步构思是我只需要给需要捕捉异常的函数添加一个装饰器,随后我们可以将该函数的各类异常分离出来,统一处理。这样就可以避免在函数中添加大量的try/except
语句。
# 伪代码
@tryme
def func():
# 需要检查的代码
print(1 / 0)
@func.exception(ZeroDivisionError)
def handle_zero_division_error(e):
# 处理ZeroDivisionError异常的代码
print(e)
这样,当func
函数发生ZeroDivisionError
异常时,就会调用handle_zero_division_error
函数来处理异常。
观察以上伪代码,首先我们在func
函数上添加了一个装饰器@tryme
,这点不难理解,而后面我们添加异常装饰器是使用@func.exception
,但是我们的func
函数并没有exception
属性,这是怎么回事呢?其实这也不难,我们只需要在@tryme
的装饰器中,将func
函数的exception
属性指向一个新的函数,这个函数的作用就是添加异常处理函数。
代码实现
from functools import wraps
from typing import Callable, Dict, Any
def tryme(func):
exception_: Dict[Any, Callable] = {}
@wraps(func)
def wrapper(*args, **kwargs):
try:
ret = func(*args, **kwargs)
if ret is not None:
return ret
except Exception as e:
handler = None
for c in exception_.keys():
if isinstance(e, c):
handler = c
if handler is None:
raise e
return exception_[handler](e)
def except_(*exceptions):
def decorator(f):
for e in exceptions:
exception_[e] = f
return f
return decorator
# 将exception属性指向except_函数
# 这样就可以使用@func.exception来添加异常处理函数
wrapper.exception = except_
return wrapper
@tryme
def my_function():
print(1 / 0)
@my_function.exception(ZeroDivisionError)
def handle_zero_division_error(e):
print('zero division error')
if __name__ == '__main__':
my_function()
这一版本中有个不太合理的地方,假设我有10个函数需要捕捉某个指定异常,岂不是要写10次@my_function.exception(ZeroDivisionError)
?这样的代码显然不够优雅,因此我们需要改进一下。使用类来封装异常装饰器,同一实例化的对象可以共享异常处理函数。
from functools import wraps
from typing import Callable, Dict, Any
class TryMe:
def __init__(self):
self.exception_: Dict[Any, Callable] = {}
def try_(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
handler = None
for c in self.exception_.keys():
if isinstance(e, c):
handler = c
if handler is None:
raise e
# 将异常发生的函数和异常对象传入异常处理函数
return self.exception_[handler](func, e)
return wrapper
def except_(self, *exceptions):
def decorator(f):
for e in exceptions:
self.exception_[e] = f
return f
return decorator
tryme = TryMe()
@tryme.try_
def my_function():
print(1 / 0)
print('hello world')
@tryme.try_
def my_function2():
print(1 / 0)
print('hello world')
@tryme.except_(ZeroDivisionError)
def handle_zero_division_error(func, e):
print(func.__name__, str(e))
if __name__ == '__main__':
my_function()
my_function2()
输出:
my_function division by zero
my_function2 division by zero
这样,我们可以统一封装异常函数,由于调用异常函数时,会传入异常发生的函数和异常对象,因此我们可以在异常函数中获取异常发生的函数的信息,比如函数名、参数等。
总结
本文不仅介绍了Python中的异常处理机制,还实现了一个简单的异常装饰器。面对多个异常需要在函数后追加各种except
语句,显得代码不够优雅,因此我们可以使用装饰器来实现异常处理,这样可以使代码更加简洁。
为此,笔者开发了一个trytry
库:
题外话
感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。
👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
👉CSDN大礼包🎁:全网最全《Python学习资料》免费赠送🆓!(安全链接,放心点击)
若有侵权,请联系删除