需求场景
在小才写python程序时,有时候需要保证程序在运行中不会因为某个方法的调用内部失败而导致整个程序的异常退出,于是我经常使用:
try:
...
except Exception as e:
print("报错原因:", e)
来捕捉异常,但是这样做有几点不太方便
- 代码冗余。一个项目的方法加上类的成员方法不知道有多少了,这样每个地方都加上try…except…无疑显得很臃肿。
- 输出报错信息不好定位。报错信息需要每个方法都定义日志头。
装饰器代码
直接上小才使用的代码(嘲笑请偷偷)
'''
报错装饰器
'''
import inspect
import time
import traceback
def check_except(error_return=None, return_error=False, show_error=True, time_log=False):
'''
:param error_return:出错时的返回值
:param return_error: 是否返回错误信息
:param show_error: 是否输出错误信息
:return:
'''
def wrapper(func):
def inner(*args, **kwargs):
rules = func.__annotations__ # 获取参数与返回值的注解
args_num = len(inspect.getfullargspec(func).args)
for name, value in kwargs.items(): # 检查传入的关键字参数类型
if name in rules:
if not isinstance(value, rules[name]):
raise RuntimeError('%s want %s, but %s' % (name, rules[name], type(value)))
try:
if time_log:
t1 = time.perf_counter()
back = func(*args[:args_num], **kwargs)
t2 = time.perf_counter()
print("[INFO] ", func.__qualname__, " 耗时:", t2 - t1)
else:
back = func(*args[:args_num], **kwargs)
if 'return' in rules and not isinstance(back, rules['return']): # 检查返回值类型
raise RuntimeError('return want %s, but %s' % (rules['return'], type(back)))
# 如果设置返回错误信息
if return_error:
# code 1表示未出错
return {"code": 1, "return": back}
else:
return back
except Exception as e:
# 如果输出错误
if show_error:
traceback.print_exc()
print("[ERROE] ", func.__qualname__, " 出错,原因:", e)
# 如果设置返回错误信息
if return_error:
# 报错返回预设置值
# code 0表示未出错
return {"code": 0, "return": error_return, "info": e}
else:
return return_error
return inner
return wrapper
小才还加上了计时的功能,一些参数可以看情况使用,只需要进行异常捕获的话,一般小才我都是直接在方法上打上@check_except()就够用了。
使用案例
if __name__ == '__main__':
@check_except()
def test():
print(1 / 0)
test()
print("小才测试异常捕获")
输出:
Traceback (most recent call last):
File “E:\learning\writing-articles\my-success\pyqt5可编辑标签页\check_except.py”, line 32, in inner
back = func(*args[:args_num], **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File “E:\learning\writing-articles\my-success\pyqt5可编辑标签页\check_except.py”, line 60, in test
print(1 / 0)
^
ZeroDivisionError: division by zero
[ERROE] test 出错,原因: division by zero
小才测试异常捕获