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

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


当前回答

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

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)

其他回答

你可以有一个专门的函数使用返回短路结果。比如这样:

def my_function_with_retries(..., max_retries=100):
    for attempt in range(max_retries):
        try:
            return my_function(...)
        except SomeSpecificException as error:
            logging.warning(f"Retrying after failed execution: {error}")

    raise SomeOtherException()

使用while和计数器:

count = 1
while count <= 3:  # try 3 times
    try:
        # do_the_logic()
        break
    except SomeSpecificException as e:
        # If trying 3rd time and still error?? 
        # Just throw the error- we don't have anything to hide :)
        if count == 3:
            raise
        count += 1

带超时的通用解决方案:

import time

def onerror_retry(exception, callback, timeout=2, timedelta=.1):
    end_time = time.time() + timeout
    while True:
        try:
            yield callback()
            break
        except exception:
            if time.time() > end_time:
                raise
            elif timedelta > 0:
                time.sleep(timedelta)

用法:

for retry in onerror_retry(SomeSpecificException, do_stuff):
    retry()

重新尝试的替代方案:坚韧和退缩(2020年更新)

重新尝试库是以前的方法,但遗憾的是,它有一些bug,自2016年以来就没有任何更新。其他的选择似乎是后退和坚韧。在写这篇文章的时候,tenacity有更多的GItHub星(2.3k vs 1.2k),并且最近更新了,因此我选择使用它。这里有一个例子:

from functools import partial
import random # producing random errors for this example

from tenacity import retry, stop_after_delay, wait_fixed, retry_if_exception_type

# Custom error type for this example
class CommunicationError(Exception):
    pass

# Define shorthand decorator for the used settings.
retry_on_communication_error = partial(
    retry,
    stop=stop_after_delay(10),  # max. 10 seconds wait.
    wait=wait_fixed(0.4),  # wait 400ms 
    retry=retry_if_exception_type(CommunicationError),
)()


@retry_on_communication_error
def do_something_unreliable(i):
    if random.randint(1, 5) == 3:
        print('Run#', i, 'Error occured. Retrying.')
        raise CommunicationError()

for i in range(100):
    do_something_unreliable(i)

上面的代码输出如下:

Run# 3 Error occured. Retrying.
Run# 5 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 6 Error occured. Retrying.
Run# 10 Error occured. Retrying.
.
.
.

坚韧的更多设置。坚韧GitHub页面上列出了重试。

在Python装饰器库中也有类似的东西。

请记住,它不测试异常,而是测试返回值。它会重新尝试,直到被修饰的函数返回True。

稍微修改一下版本就可以了。