在python自动化领域,往往要用到pyautogui,pywin32等模块实现自动化操作。然而,这种自动化操作,本身具有一定的局限性,其中最主要的一个问题就是,一旦执行结果不按照脚本预设的来执行,往往会抛出异常,导致程序中断。
解决这个问题,主要有这么几种思路:
第一,每一次操作后分情况讨论。这种方法的弊端是代码过于冗长,不够直观。
第二,对异常进行处理,例如重启函数。但是这里遇到一个问题,重启次数是多少,怎么避免循环,如何根据异常类型实时修改重启函数的参数,对异常的后处理操作后如何再次重启回归正轨等等。要解决这些问题,代码逻辑复杂。
基于这个原因,本文实现通过装饰器,实现了对函数的封装。主要有以下几个功能:
1、指定重启函数的次数。
2、限定重启函数的重启时间。
3、可以指定异常处理函数,在抛出异常后,执行处理函数,然后再次尝试重启。
4、可以根据函数重启的次数,传入不同的参数值。
其代码如下:
(1)修饰器部分:
def retryOnException(maxAttempts=3, delay=1, exceptions=(Exception,), timeout=None, onFail=None, paramModifier=incrementParam):
def decorator(func):
def wrapper(*args, **kwargs):
startTime = time.time()
attempts = 0
while attempts < maxAttempts:
if paramModifier:
new_args, new_kwargs, args, kwargs = paramModifier(*args, **kwargs)
try:
return func(*new_args, **new_kwargs)
except exceptions as e:
print("An exception occured:{}".format(e))
print("Attempting to retry... Attempt {}/{}".format(attempts+1, maxAttempts))
time.sleep(delay)
attempts += 1
if timeout and time.time() - startTime > timeout:
if onFail:
result = onFail(*args, **kwargs)
if result is not None: #表明问题已经修复了
attempts = 0 #重置尝试次数
continue
else:
#表明问题没有修复,执行没有结果
raise RuntimeError(
"Function {} failed after {} onFail.".format(func.__name__, maxAttempts))
else:
raise TimeoutError("Function {} time out after {} seconds.".format(func.__name__, timeout))
if onFail:
result = onFail(*args, **kwargs)
if result is not None: # 表明问题已经修复了
return wrapper(*args, **kwargs)
else:
# 表明问题没有修复,执行没有结果
raise RuntimeError(
"Function {} failed after {} onFail.".format(func.__name__, maxAttempts))
else:
raise RuntimeError("Function {} failed after {} attempts.".format(func.__name__, maxAttempts))
return wrapper
return decorator
(2)参数选择器
def incrementParam(*args, **kwargs):
if "increment" in kwargs:
index = kwargs["increment"]
kwargs["increment"] += 1
new_args, new_kwargs = kwargs["argsList"][index] #{"increment":0, "argsList":[([],{}),]}
return new_args, new_kwargs, args, kwargs
else:
return args, kwargs, args, kwargs
(3)异常处理函数和主程序代码
def hello(*args, **kwargs):
print("处理异常情况部分")
return None
@retryOnException(maxAttempts=3, delay=2, timeout=10, onFail=hello)
def testFunction(a, b, c, good):
print("trying to excute function...")
print(a, b, c, good)
import random
if random.randint(0, 0) == 0:
raise ValueError("someting went wrong!")
return "Function executed successfully"
try:
print(testFunction(increment = 0, argsList = [([1,2,3,4], {}), ([2,2,2,1],{}), ([3,4,3], {"good":3})]))
except(RuntimeError, TimeoutError) as e:
print("================")
print(str(e))
try:
print( testFunction(1, 2, "yes", good="yes") )
except Exception as e:
print("huhuu")
pass
以上代码非常简洁,可以完美实现对函数异常的重启处理,并且具有一定的异常修复功能。例如:在微信自动化程序项目中,由于交互问题导致的偶发性发送信息或者文件失败,可以通过该方法实现异常判别并自动处理,具有比较好的代码稳定性。