Comment réessayer après exception?
-
21-09-2019 - |
Question
J'ai une boucle commençant par for i in range(0, 100)
. Normalement, il fonctionne correctement, mais parfois il échoue en raison des conditions du réseau. À l'heure actuelle, je l'ai réglé de telle sorte que en cas d'échec, il continue
à l'exception de l'alinéa (continuer sur le numéro suivant pour i
).
moi Est-il possible de réaffecter le même numéro à i
et courir à travers l'itération de la boucle a échoué à nouveau?
La solution
Faites un while True
dans votre boucle, mettez votre code try
à l'intérieur, et de briser cette boucle de while
que lorsque votre code réussit.
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
Autres conseils
Je préfère limiter le nombre de réitérations, de sorte que s'il y a un problème avec ce point précis, vous finirez par continuer sur la suivante, ainsi:
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.
Le package est réessayant une belle façon de réessayer un bloc de code en cas d'échec.
Par exemple:
@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")
Voici une solution similaire à d'autres, mais il soulèvera l'exception si elle ne réussit pas dans le nombre prescrit ou relances.
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
L'approche plus « fonctionnelle » sans utiliser les laids while:
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
La façon la plus claire serait de définir explicitement i
. Par exemple:
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
Utilisation récursivité
for i in range(100):
def do():
try:
## Network related scripts
except SpecificException as ex:
do()
do() ## invoke do() whenever required inside this loop
Une solution générique avec un délai d'attente:
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)
Utilisation:
for retry in onerror_retry(SomeSpecificException, do_stuff):
retry()
Il y a quelque chose de similaire dans le Python décorateur Bibliothèque .
S'il vous plaît garder à l'esprit qu'il ne teste pas des exceptions, mais la valeur de retour. Il réessaie jusqu'à ce que la fonction décorée retourne True.
Une version légèrement modifiée devrait faire l'affaire.
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
Ma version est similaire à plusieurs de ce qui précède, mais ne pas utiliser une boucle de while
séparée et re-raise la dernière exception si toutes les tentatives échouent. Pourrait définir explicitement err = None
en haut, mais pas strictement nécessaire car il ne doit exécuter le bloc de else
finale s'il y avait une erreur et donc err
est réglé.
Utilisation de temps et un compteur:
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
Si vous voulez une solution sans boucles imbriquées et l'invocation break
sur le succès que vous pourriez développeur un retriable
wrap rapide pour tout itérable. Voici un exemple d'un problème de mise en réseau que je rencontre souvent - sauvé l'authentification expire. L'utilisation de ce lirait comme ceci:
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
J'utilise suivre dans mes codes,
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
avec mon python sur une solution à ce problème et je suis heureux de partager avec les visiteurs stackoverflow s'il vous plaît donner des commentaires si elle est nécessaire.
print("\nmonthly salary per day and year converter".title())
print('==' * 25)
def income_counter(day, salary, month):
global result2, result, is_ready, result3
result = salary / month
result2 = result * day
result3 = salary * 12
is_ready = True
return result, result2, result3, is_ready
i = 0
for i in range(5):
try:
month = int(input("\ntotal days of the current month: "))
salary = int(input("total salary per month: "))
day = int(input("Total Days to calculate> "))
income_counter(day=day, salary=salary, month=month)
if is_ready:
print(f'Your Salary per one day is: {round(result)}')
print(f'your income in {day} days will be: {round(result2)}')
print(f'your total income in one year will be: {round(result3)}')
break
else:
continue
except ZeroDivisionError:
is_ready = False
i += 1
print("a month does'nt have 0 days, please try again")
print(f'total chances left: {5 - i}')
except ValueError:
is_ready = False
i += 1
print("Invalid value, please type a number")
print(f'total chances left: {5 - i}')
Voici mon idée sur la façon de résoudre ce problème:
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)
incrémenter la variable de boucle uniquement lorsque la clause try réussit