类外的装饰器方法装饰类方法,并调用该类的其他方法
场景:链接数据库的类,在执行数据库方面的操作时,经常会断开,此时需要调用该类的连接数据库方法来重新链接到数据库
class My_dbclient():
def __init__(self):
self.try_count=10
self.connect()
def connect(self):
print("数据库链接成功")
def insert(self):
# 可能会出现数据库断开链接的异常
print("正在执行保存操作")
for i in range(self.try_count):
try:
print("保存数据")
# raise NameError
return
except Exception:
time.sleep(1)
self.connect()
print(traceback.format_exc())
def select(self):
# 可能会出现数据库断开链接的异常
print("查询数据")
def delete(self):
# 可能会出现数据库断开链接的异常
print("删除数据")
就像 insert 方法中这样,可以捕获异常,并重新链接,然后再操作。
但是,无论增删改查,都需要这样来写,代码冗余。很自然,使用装饰器来解决。
示例:
常规的装饰器写法
def catch_error(fun):
def wrapper(*args, **kwargs):
for i in range(1, 10):
try:
fun(*args, **kwargs)
return
except Exception:
time.sleep(1)
print("链接错误 ---{}--- 次".format(i))
print("调用数据库链接方法,重新链接数据库")
print("信息保存失败")
return wrapper
@catch_error
def insert():
print("开始执行插入语句")
raise TimeoutError
现在我们想要装饰类方法,并在捕获数据库链接异常后,调用数据库链接方法重新链接。
解决办法:在装饰器的内部函数 wrapper 的参数中,增加 self 这个参数, 如下,就可以使用 self 来调用 connect 这个方法了。
def catch_error(fun):
def wrapper(self,*args, **kwargs):
for i in range(1, 10):
try:
fun(*args, **kwargs)
return
except Exception:
time.sleep(1)
print("链接错误 ---{}--- 次".format(i))
print("调用数据库链接方法,重新链接数据库")
self.connect()
print("信息保存失败")
return wrapper
完整代码:
import time
import traceback
def catch_error(fun):
def wrapper(self,*args, **kwargs):
for i in range(1, 10):
try:
fun(*args, **kwargs)
return
except Exception:
time.sleep(1)
print("链接错误 ---{}--- 次".format(i))
print("调用数据库链接方法,重新链接数据库")
self.connect()
print("信息保存失败")
return wrapper
@catch_error
def insert():
print("开始执行插入语句")
raise TimeoutError
class My_dbclient():
def __init__(self):
self.try_count = 10
self.connect()
def connect(self):
print("数据库链接成功")
@catch_error
def insert(self):
# 可能会出现数据库断开链接的异常
print("保存数据")
raise TimeoutError
def select(self):
# 可能会出现数据库断开链接的异常
print("查询数据")
def delete(self):
# 可能会出现数据库断开链接的异常
print("删除数据")
if __name__ == '__main__':
t = My_dbclient()
t.insert()
但是,这里面有个坑:
- 在这个装饰器中,捕获异常,必须使用 Exception 来捕获!而不能是其他的异常,即使引发的异常和要捕获的异常是同一个异常也不行。
- 装饰普通函数则没有影响
如下:
def catch_error(fun):
def wrapper(self,*args, **kwargs):
for i in range(1, 10):
try:
fun(*args, **kwargs)
return
except NameError:
time.sleep(1)
print("链接错误 ---{}--- 次".format(i))
print("调用数据库链接方法,重新链接数据库")
self.connect()
print("信息保存失败")
return wrapper
@catch_error
def insert(self): # 类方法
# 可能会出现数据库断开链接的异常
print("保存数据")
raise NameError
数据库链接成功
Traceback (most recent call last):
File "D:/test.py", line 54, in <module>
t.insert()
File "D:/test.py", line 9, in wrapper
fun(*args, **kwargs)
TypeError: insert() missing 1 required positional argument: 'self'
这篇文章借鉴了靑南大佬的公号文章:
https://mp.weixin.qq.com/s?__biz=MzI2MzEwNTY3OQ==&mid=2648978488&idx=1&sn=4fc271eebbb88273cb7f280b3b1389f5&chksm=f25069d8c527e0cecc3e62f431a0c3a92d425345f18f37b7f7bbf2b12e0578d725197480583a&mpshare=1&scene=1&srcid=&sharer_sharetime=1592892345783&sharer_shareid=463653a5a10c5bdfdaa178eb8a3a2da0&key=32686516f8c11656ca6208b19edd6c0d7b1e05bbe9fb0be63d3b0d9a00dab386c78b3177eba6325998d7f52dc70242b1eae81a0550cb1b5d5d5ac8a9cebf29d920dc5436e71606e81ea34c9ed54ebb91&ascene=1&uin=MjE2MTA1ODMxMg%3D%3D&devicetype=Windows+10&version=62070158&lang=zh_CN&exportkey=AWW29fqNMgGY6iLMschplCM%3D&pass_ticket=fpX5pWKrl3sa09YyD4bLp3t7V9wWI6%2BY7Bf1Umfke7FK8Xgia4WMG3wnNRiAmh4D