我有一个循环,开头为for I,范围为(0,100)。正常情况下,它可以正常运行,但有时由于网络条件而出现故障。目前,我已经设置它,以便在失败时,它将继续在except子句中(继续到I的下一个数字)。

我是否可以将相同的数字重新分配给i,并再次运行失败的循环迭代?


当前回答

使用这个装饰器,您可以轻松地控制错误

class catch:
    def __init__(self, max=1, callback=None):
        self.max = max 
        self.callback = callback 
    
    def set_max(self, max):
        self.max = max
    
    def handler(self, *args, **kwargs):
        self.index = 0
        while self.index < self.max: 
            self.index += 1
            try:
                self.func(self, *args, **kwargs)
        
            except Exception as error:
                if callable(self.callback):
                    self.callback(self, error, args, kwargs)
                
    def __call__(self, func):
        self.func = func
        return self.handler

import time
def callback(cls, error, args, kwargs):
    print('func args', args, 'func kwargs', kwargs)
    print('error', repr(error), 'trying', cls.index)
    if cls.index == 2:
        cls.set_max(4)
    
    else:
        time.sleep(1)
    
    
@catch(max=2, callback=callback)  
def test(cls, ok, **kwargs):
    raise ValueError('ok')

test(1, message='hello')

其他回答

for _ in range(5):
    try:
        # replace this with something that may fail
        raise ValueError("foo")

    # replace Exception with a more specific exception
    except Exception as e:
        err = e
        continue

    # no exception, continue remainder of code
    else:
        break

# did not break the for loop, therefore all attempts
# raised an exception
else:
    raise err

我的版本与上面的几个类似,但没有使用单独的while循环,如果所有重试都失败,则重新引发最新的异常。可以显式地在顶部设置err = None,但不是严格必要的,因为它只应该在出现错误时执行最后一个else块,因此设置了err。

只有当try子句成功时才增加循环变量

我使用这个,它可以用于任何函数:

def run_with_retry(func: callable, max_retries: int = 3, wait_seconds: int = 2, **func_params):
num_retries = 1
while True:
    try:
        return func(*func_params.values())
    except Exception as e:
        if num_retries > max_retries:
            print('we have reached maximum errors and raising the exception')
            raise e
        else:
            print(f'{num_retries}/{max_retries}')
            print("Retrying error:", e)
            num_retries += 1
            sleep(wait_seconds)

像这样调用:

    def add(val1, val2):
        return val1 + val2

    run_with_retry(func=add, param1=10, param2=20)

这里有一个快速装饰器来处理这个问题。7行,没有依赖关系。

def retry(exception=Exception, retries=3, delay=0):
    def wrap(func):
        for i in range(retries):
            try:
                return func()
            except exception as e:
                print(f'Retrying {func.__name__}: {i}/{retries}')
                time.sleep(delay)
        raise e
    return wrap

@retry()
def do_something():
  ...
@retry(HTTPError, retries=100, delay=3)
def download_something():
  ...

可以添加的一个功能是扩展异常以处理多个异常(splat一个列表)。

我在我的代码中使用following,

   for i in range(0, 10):
    try:
        #things I need to do
    except ValueError:
        print("Try #{} failed with ValueError: Sleeping for 2 secs before next try:".format(i))
        time.sleep(2)
        continue
    break