python 装饰器实践,实现定时函数和失败异常重复调用
执行请求或函数,出现异常情况下指定重复执行次数
可以作为一个包调用
方法 get()和post 做请求,execcunt = 指定请求失败再次请求次数
方法loopExecution作为装饰器,循环执行函数,execcunt = 指定异常再次执行次数
#函数异常情况下再次执行,执行次数
import traceback
def loopExecution(func):
def wrapper(*args,**kwargs):
count = kwargs.pop("execcount", 1)
try:
res = func(*args,**kwargs)
except Exception as err:
for i in range(count):
try:
res = func(*args,**kwargs)
if isinstance(res,Exception):
return res
except Exception as err:
pass
#失败到达限定值返回异常信息
return traceback.format_exc()
# return None
return res
return wrapper
@loopExecution
def func():
print("我是一个函数")
raise Exception("执行失败了")
if __name__ == '__main__':
data = func(execcount=6)
print("多次失败情况下返回的数据:",data)
通用请求,指定请求次数,将其作为一个包调用,如包名为my_request
import my_reqeust
response = my_request.get(url)
import time
import requests
import traceback
from requests import Session
from functools import partial
session = Session()
traceback_info = None
def outer(func):
def wrapper(*args,**kwargs):
count = kwargs.pop("execcount", 1)
res = func(*args,**kwargs)
if isinstance(res, Exception):
for i in range(count):
print(i)
res = func(*args,**kwargs)
if not isinstance(res, Exception):
break
if isinstance(res, Exception):
return None
return res
return wrapper
@outer
def publicRequsts(*args,**kwargs):
"""通用请求方法"""
method = args[0] if len(args) is 1 else kwargs.pop("method", "GET")
if not method in ("GET","POST"):
raise Exception("The request method is illegal")
url = args[1] if len(args) is 2 else kwargs.pop("url", None)
if url is None or not isinstance(url,str) or not "http" in url:
raise Exception("The URL is illegal")
try:
response = session.request(method, url,**kwargs)
print("="*10)
except Exception as err:
global traceback_info
traceback_info = traceback.format_exc()
return err
return response
get = partial(publicRequsts, "GET")
post = partial(publicRequsts, "POST")
使用线程对执行函数限制执行时间,可不加定时为非阻塞,加定时间到会强制停止线程
from threading import Thread
import threading
import inspect
import ctypes
def _async_raise(tid, exctype):
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
def timelimited(exectime=None):
def decorator(function):
def decorator2(*args, **kwargs):
time_out = exectime if not exectime is None else kwargs.pop("exectime",None)
if time_out is None:
return Exception("exec time param missing ")
class TimeLimited(threading.Thread):
def __init__(self, _error=None, ):
Thread.__init__(self)
self._error = _error
self._result = None
def run(self):
try:
result = function(*args, **kwargs)
if result is None:
self._result = True
else:
self._result = result
except Exception as err:
self._error = Exception(err)
t = TimeLimited()
t.setDaemon(True)
t.start()
if not time_out is False:
t.join(time_out)
if isinstance(t._error, Exception):
return t._error
else:
if t._result is None:
stop_thread(t)
return Exception("Time out!")
else:
return t._result
return decorator2
return decorator
@timelimited(exectime=3)# 设置运行超时时间S,优先使用,exectime=False是不加定时
def func():
time.sleep(5)
print("==========")
print("==========")
print("==========")
print("==========")
return "aaaa"
if __name__ == "__main__":
print(func())
time.sleep(4)
print(threading.enumerate())
time.sleep(6)