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

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


当前回答

以下是我关于如何解决这个问题的想法:

j = 19
def calc(y):
    global j
    try:
        j = j + 8 - y
        x = int(y/j)   # this will eventually raise DIV/0 when j=0
        print("i = ", str(y), " j = ", str(j), " x = ", str(x))
    except:
        j = j + 1   # when the exception happens, increment "j" and retry
        calc(y)
for i in range(50):
    calc(i)

其他回答

使用递归

for i in range(100):
    def do():
        try:
            ## Network related scripts
        except SpecificException as ex:
            do()
    do() ## invoke do() whenever required inside this loop

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

我喜欢使用bool值,如下所示:

success = False
num_try = 0
while success is False:
    if num_try >= 10: # or any number
        # handle error how  you please
    try:
        # code
        success = True
    except Exception as e:
        # record or do something with exception if needed
        num_try += 1

我喜欢laurent-laporte的回答。下面是我的版本,它包装在一个类与静态方法和一些例子。我实现了重试计数作为另一种重试方式。还增加了kwargs。

from typing import List
import time


class Retry:
    @staticmethod
    def onerror_retry(exception, callback, retries: int = 0, timeout: float = 0, timedelta: float = 0,
                      errors: List = None, **kwargs):
        """

        @param exception: The exception to trigger retry handling with.
        @param callback: The function that will potentially fail with an exception
        @param retries: Optional total number of retries, regardless of timing if this threshold is met, the call will
                        raise the exception.
        @param timeout: Optional total amount of time to do retries after which the call will raise an exception
        @param timedelta: Optional amount of time to sleep in between calls
        @param errors: A list to receive all the exceptions that were caught.
        @param kwargs: An optional key value parameters to pass to the function to retry.
        """
        for retry in Retry.__onerror_retry(exception, callback, retries, timeout, timedelta, errors, **kwargs):
            if retry: retry(**kwargs)  # retry will be None when all retries fail.

    @staticmethod
    def __onerror_retry(exception, callback, retries: int = 0, timeout: float = 0, timedelta: float = 0,
                        errors: List = None, **kwargs):
        end_time = time.time() + timeout
        continues = 0
        while True:
            try:
                yield callback(**kwargs)
                break
            except exception as ex:
                print(ex)
                if errors:
                    errors.append(ex)

                continues += 1
                if 0 < retries < continues:
                    print('ran out of retries')
                    raise

                if timeout > 0 and time.time() > end_time:
                    print('ran out of time')
                    raise
                elif timedelta > 0:
                    time.sleep(timedelta)


err = 0

#
# sample dumb fail function
def fail_many_times(**kwargs):
    global err
    err += 1
    max_errors = kwargs.pop('max_errors', '') or 1
    if err < max_errors:
        raise ValueError("I made boo boo.")
    print("Successfully did something.")

#
# Example calls
try:
    #
    # retries with a parameter that overrides retries... just because
    Retry.onerror_retry(ValueError, fail_many_times, retries=5, max_errors=3)
    err = 0
    #
    # retries that run out of time, with 1 second sleep between retries.
    Retry.onerror_retry(ValueError, fail_many_times, timeout=5, timedelta=1, max_errors=30)
except Exception as err:
    print(err)

重新尝试的替代方案:坚韧和退缩(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页面上列出了重试。