2010-01-18 5 views
125

Ich habe eine Schleife beginnend mit for i in range(0, 100). Normalerweise wird es korrekt ausgeführt, aber manchmal schlägt es aufgrund der Netzwerkbedingungen fehl. Derzeit habe ich es so eingestellt, dass bei einem Fehler, es continue in der Ausnahme-Klausel (weiter zur nächsten Nummer für i).Wie wiederhole ich nach einer Ausnahme in Python?

Kann ich dieselbe Nummer i erneut zuweisen und die fehlerhafte Iteration der Schleife erneut durchlaufen?

+0

Sie können 'range (100)' ohne den ersten Parameter verwenden. Wenn Sie Python 2.x verwenden, können Sie sogar 'xrange (100)' verwenden, dies erzeugt einen Iterator und verbraucht weniger Speicher. (Nicht, dass es mit nur 100 Objekten von Bedeutung ist.) –

+1

mögliches Duplikat von [gibt es einen pythonischen Weg, um etwas bis zu einer maximalen Anzahl von Malen zu versuchen?] (Http://stackoverflow.com/questions/567622/is-there- a-pythonic-way-to-try-some-up-to-a-maximum-of-times) –

+3

Diese Frage könnte hilfreich sein: [Gibt es eine pythische Möglichkeit, etwas bis zu einer maximalen Anzahl von Malen zu versuchen? ] (http://stackoverflow.com/questions/567622/is-there-a-pythonicway-to-try-omething-up-to-a-maximum-number-of-times) –

Antwort

213

Tun Sie eine while True innerhalb Ihrer for-Schleife, setzen Sie Ihre try Code innerhalb, und brechen Sie von dieser while Schleife nur, wenn Ihr Code erfolgreich ist.

for i in range(0,100): 
    while True: 
     try: 
      # do stuff 
     except SomeSpecificException: 
      continue 
     break 
+31

Außer 'außer SomeSpecificError:' 'anstatt alle Ausnahmen abzufangen. –

+0

'continue' verwendet nicht das gleiche Element des Iterablen; stattdessen geht es weiter zum nächsten. –

+0

@Ignacio: ja; Wo ist das Problem? – zneak

6

Der klarste Weg wäre, explizit i zu setzen. diese hässlichen While-Schleifen ohne

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

    except MyException: 
     continue 
+31

Ist das C oder C++? Ich kann es nicht sagen. –

+2

@Georg Das ist Python, wie in der Frage angegeben. Oder wo bist du aus irgendeinem Grund sarkastisch? –

+1

Dies ist nicht das, was das OP verlangt. Es könnte sein, wenn Sie 'i + = 1' direkt nach' # do stuff' setzen. –

-9

Erhöhung der Schleife Variable nur, wenn die try-Klausel

+8

-1, Ausarbeitung ist nett, wie sind Grammatik und Interpunktion. –

9

Je mehr „funktional“ Ansatz erfolgreich ist:

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

tryAgain() 
+10

Es tut mir leid, aber es scheint viel hässlicher als die "hässlichen while loops" Varianten; und ich mag funktionale Programmierung ... – lvella

+6

Sie müssen sicherstellen, dass Sie nicht tief durchforsten - die Standard-Stack-Größe in Python ist 1000 –

+2

Wenn dies "funktional" ist, sollte die Rekursion wie folgt lauten: 'except : tryAgain (retries + 1) ' – quamrana

3

es etwas ähnliches in der ist zum Beispiel Python Decorator Library.

Bitte beachten Sie, dass nicht auf Ausnahmen geprüft wird, sondern der Rückgabewert. Es wiederholt sich, bis die dekorierte Funktion True zurückgibt.

Eine leicht modifizierte Version sollte den Trick tun.

+0

Hier ist, wie Sie es für Ausnahmen ändern können http://www.salzycrane.com/blog/2009/11/trying-out-retry-decorator-python/ –

107

Ich ziehe die Anzahl der Wiederholungen zu begrenzen, so dass, wenn es ein Problem mit diesem speziellen Punkt ist werden Sie schließlich auf die nächsten weiter, also:

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. 
+0

Was sind die Folgen der zweiten "else" bezieht sich auf die Flusskontrolle? Unter welchen Umständen wird der "we failed ..." Teil des Codes ausgeführt? – g33kz0r

+0

@ g33kz0r Das for-else-Konstrukt in Python führt die else-Klausel aus, wenn die for-Schleife nicht bricht. In diesem Fall wird dieser Abschnitt ausgeführt, wenn wir alle 10 Versuche versuchen und immer eine Ausnahme erhalten. – xorsyst

+2

Dies ist eine großartige Antwort! Wirklich verdient mehr Upvotes. Es nutzt perfekt alle Möglichkeiten in Python, insbesondere die weniger bekannte 'else:' -Klausel von 'for'. – pepoluan

38

Die retrying package eine nette Art und Weise ist eine erneut zu versuchen Codeblock bei Fehler.

Zum Beispiel:

@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" 
+1

Generell hat pypi mehrere Pakete für Wiederholungs Dekorateure: https://pypi.python.org/pypi?%3Aaction=search&term=retry+decorator&submit=search – kert

4

Eine generische Lösung mit einem Timeout:

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) 

Verbrauch:

for retry in onerror_retry(SomeSpecificException, do_stuff): 
    retry() 
+0

Ist es möglich, eine eigene Funktion für die Fehlerprüfung angeben? Es würde die Ausgabe des Callbacks nehmen und an die Fehlerüberprüfungsfunktion übergeben, um zu entscheiden, ob es ein Fehler oder ein Erfolg war, anstatt eine einfache Ausnahme zu verwenden: –

+0

Anstelle eines "try ... excepts" kann ein 'if' verwendet werden Erklärung. Aber es ist weniger Python. –

-3

Hier ist meine Idee, wie diese zu beheben:

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) 
+6

Das ist weit weg von der Basis. –

8

Hier ist eine Lösung ähnlich zu anderen, aber es wird die Ausnahme auslösen, wenn es in der vorgeschriebenen Anzahl oder Wiederholungen nicht gelingt.

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 
+0

Großer Fang @notpeter. Fest. – TheHerk

+0

Schöne Antwort, aber der Variablenname 'retries' ist irreführend. Es sollte viel lieber "probiert" werden. – Lukas

+0

Wahr @Lukas. Fest. – TheHerk

2

Verwendung während und einen Zähler:

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 
3

Rekursion

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

Sie können Python verwenden retrying Paket. Retrying

Es ist in Python geschrieben, um die Aufgabe zu vereinfachen, Wiederholungsverhalten zu fast allem hinzuzufügen.

Verwandte Themen