Как повторить попытку после исключения? - PullRequest
201 голосов
/ 18 января 2010

У меня есть цикл, начинающийся с for i in range(0, 100).Обычно он работает правильно, но иногда происходит сбой из-за условий сети.В настоящее время он настроен таким образом, чтобы при сбое он был continue в предложении кроме (переходите к следующему номеру для i).

Могу ли я переназначить тот же номер на i и снова выполнить неудачную итерацию цикла?

Ответы [ 16 ]

311 голосов
/ 18 января 2010

Сделайте while True внутри вашего цикла for, поместите свой код try внутрь и выходите из цикла while только тогда, когда ваш код завершится успешно.

for i in range(0,100):
    while True:
        try:
            # do stuff
        except SomeSpecificException:
            continue
        break
152 голосов
/ 05 октября 2011

Я предпочитаю ограничить количество повторных попыток, чтобы в случае проблем с этим конкретным элементом вы в конечном итоге переходили к следующему, таким образом:

for i in range(100):
  for attempt in range(10):
    try:
      # do thing
    except:
      # perhaps reconnect, etc.
    else:
      break
  else:
    # we failed all the attempts - deal with the consequences.
55 голосов
/ 18 сентября 2014

Пакет повторных попыток - хороший способ повторить блок кода при ошибке.

Например:

@retry(wait_random_min=1000, wait_random_max=2000)
def wait_random_1_to_2_s():
    print("Randomly wait 1 to 2 seconds between retries")
17 голосов
/ 19 января 2016

Вот решение, подобное другим, но оно вызовет исключение, если оно не преуспеет в заданном числе или повторных попыток.

tries = 3
for i in range(tries):
    try:
        do_the_thing()
    except KeyError as e:
        if i < tries - 1: # i is zero indexed
            continue
        else:
            raise
    break
14 голосов
/ 29 октября 2010

Более «функциональный» подход без использования этих уродливых циклов while:

def tryAgain(retries=0):
    if retries > 10: return
    try:
        # Do stuff
    except:
        retries+=1
        tryAgain(retries)

tryAgain()
9 голосов
/ 18 января 2010

Самый ясный способ - явно установить i. Например:

i = 0
while i < 100:
    i += 1
    try:
        # do stuff

    except MyException:
        continue
5 голосов
/ 31 августа 2016

Использование рекурсии

for i in range(100):
    def do():
        try:
            ## Network related scripts
        except SpecificException as ex:
            do()
    do() ## invoke do() whenever required inside this loop
5 голосов
/ 04 декабря 2014

Общее решение с таймаутом:

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()
4 голосов
/ 15 июня 2011

В библиотеке Python Decorator .

есть нечто похожее.

Имейте в виду, что он проверяет не исключения, а возвращаемое значение. Повторяется до тех пор, пока оформленная функция не вернет True.

Слегка измененная версия должна сработать.

2 голосов
/ 05 февраля 2019
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 установлено.

...