Как повторить попытку после исключения?
У меня есть цикл, начинающийся с for i in range(0, 100)
. Обычно он работает правильно, но иногда он терпит неудачу из-за сетевых условий. В настоящее время я настроен так, что при ошибке он будет continue
в предложении except (перейдите к следующему номеру для i
).
Возможно ли, чтобы я переназначил тот же номер до i
и снова пропустил неудачную итерацию цикла?
Ответы
Ответ 1
Сделайте while True
внутри цикла for, поместите код try
внутри и перерыв в этом цикле while
только тогда, когда ваш код преуспеет.
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
Ответ 2
Я предпочитаю ограничивать количество повторений, так что, если есть проблема с этим конкретным элементом, вы, в конце концов, перейдете к следующему:
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.
Ответ 3
Пакет повторных попыток - это хороший способ повторить блок кода при ошибке.
Например:
@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")
Ответ 4
Вот решение, подобное другим, но оно приведет к возникновению исключения, если ему не удастся выполнить заданное число или повторить попытку.
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
Ответ 5
Более "функциональный" подход без использования этих уродливых циклов while:
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
Ответ 6
Самый ясный способ - явно установить i
. Например:
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
Ответ 7
Общее решение с тайм-аутом:
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()
Ответ 8
В библиотеке Python Decorator есть нечто похожее.
Пожалуйста, имейте в виду, что это не проверка исключений, а возвращаемое значение. Повторяется до тех пор, пока оформленная функция не вернет True.
Немного измененная версия должна сделать свое дело.
Ответ 9
Использование рекурсии
for i in range(100):
def do():
try:
## Network related scripts
except SpecificException as ex:
do()
do() ## invoke do() whenever required inside this loop
Ответ 10
Использование 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
Ответ 11
Вы можете использовать пакет повторной проверки Python.
Retrying
Это написано на Python, чтобы упростить задачу добавления поведения повтора к чему угодно.
Ответ 12
Если вы хотите найти решение без вложенных циклов и использования break
при успехе, вы можете разработать быструю retriable
для любой итерации. Вот пример сетевой проблемы, с которой я часто сталкиваюсь - срок сохраненной аутентификации истекает. Использование этого будет читать так:
client = get_client()
smart_loop = retriable(list_of_values):
for value in smart_loop:
try:
client.do_something_with(value)
except ClientAuthExpired:
client = get_client()
smart_loop.retry()
continue
except NetworkTimeout:
smart_loop.retry()
continue
Ответ 13
Я использую следующие в моих кодах,
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
Ответ 14
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
.
Ответ 15
Вот моя идея о том, как это исправить:
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)
Ответ 16
увеличивает вашу переменную цикла только тогда, когда предложение try успешно