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. Actuellement, je l'ai configuré pour qu'en cas d'échec, il sera continue
dans la clause except (passez au numéro suivant pour i
).
Est-il possible pour moi de réaffecter le même numéro à i
et de réexécuter l'itération échouée de la boucle?
Faites un while True
à l'intérieur de votre boucle for, mettez votre code try
à l'intérieur et coupez cette boucle while
uniquement lorsque votre code réussit.
for i in range(0,100):
while True:
try:
# do stuff
except SomeSpecificException:
continue
break
Je préfère limiter le nombre de tentatives, de sorte que s'il y a un problème avec cet élément spécifique, vous passerez éventuellement au suivant, 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 nouvelle tentative de package est un bon moyen 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 solutions, mais elle lève l'exception si elle ne réussit pas dans le nombre prescrit ou si elle réessaye.
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 la plus "fonctionnelle" sans utiliser ces vilaines boucles while:
def tryAgain(retries=0):
if retries > 10: return
try:
# Do stuff
except:
retries+=1
tryAgain(retries)
tryAgain()
Le moyen le plus clair serait de définir explicitement i
. Par exemple:
i = 0
while i < 100:
i += 1
try:
# do stuff
except MyException:
continue
Utiliser la récursion
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)
Usage:
for retry in onerror_retry(SomeSpecificException, do_stuff):
retry()
Il y a quelque chose de similaire dans = Python Decorator Library .
N'oubliez pas qu'il ne teste pas les 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 des précédentes, mais n'utilise pas de boucle while
distincte et lève à nouveau la dernière exception si toutes les tentatives échouent. Peut définir explicitement err = None
en haut, mais pas strictement car il ne doit exécuter que le dernier bloc else
en cas d'erreur et donc err
est défini.
Utilisation de while et d'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
Vous pouvez utiliser le package Python retrying. Réessayer
Il est écrit en Python pour simplifier la tâche consistant à ajouter un comportement de nouvelle tentative à peu près n'importe quoi.
Si vous voulez une solution sans boucles imbriquées et appelant break
en cas de succès, vous pouvez développer rapidement et rapidement retriable
pour tout élément itératif. Voici un exemple de problème de réseau que je rencontre souvent - l'authentification enregistrée expire. Son utilisation se 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 ce qui suit 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