2016-02-19 2 views
17

Bedenken Sie:Break-Anweisung schließlich in Block Schwalben Ausnahme

def raiseMe(text="Test error"): 
    raise Exception(text) 

def break_in_finally_test(): 
    for i in range(5): 
     if i==2: 
      try: 
       raiseMe() 
      except: 
       raise 
      else: 
       print "succeeded!" 
      finally: 
       print "testing this!" 
       break 

if __name__=='__main__': 
    break_in_finally_test() 

Ich erwartete Exception("Test error") zu sehen angehoben werden, sondern nur „Testen dieses“ gedruckt wird. Die Absicht war natürlich, raiseMe() nur einmal anzurufen, egal ob wir Erfolg haben oder nicht - aber wenn es eine Ausnahme macht, hätte ich das sehen wollen!

Warum schluckt Pause die Ausnahme, die ich explizit erhöhe?

+0

Ich bin mir nicht sicher, warum genau das passiert (und finde es ein wenig überraschend), aber du könntest stattdessen in "else" einbrechen, weil es im Ausnahmefall sowieso aus der Schleife austritt. – bereal

+0

Ich kann verstehen, wie "Rückkehr" in endlich funktioniert, aber mit "Pause" ist es einfach komisch. Ihr Beispiel deckt dies nicht ab, aber die Methode wird sogar nach der Schleife weiter ausgeführt! –

Antwort

28

Von https://docs.python.org/2.7/reference/compound_stmts.html#finally:

Wenn schließlich vorhanden ist, gibt es eine ‚Bereinigung‘ Handler. Die try-Klausel ist
ausgeführt, einschließlich aller außer-und-else-Klauseln. Wenn eine Ausnahme in
eine der Klauseln auftritt und nicht behandelt wird, wird die Ausnahme vorübergehend gespeichert.
Die finally-Klausel wird ausgeführt. Wenn es eine gespeicherte Ausnahme gibt, wird sie am Ende der finally-Klausel
re-raised. Wenn die finally-Klausel hebt
eine weitere Ausnahme oder führt eine Rückkehr oder eine Erklärung brechen, die gespeicherte
Ausnahme
verworfen

Dies spiegelt auch das Verhalten der try...finally Aussage erwartet vor PEP341:

Dies ist, wie ein Versuch außer schließlich sah Block wie vor PEP341:

try: 
    try: 
     raiseMe() 
    except: 
     raise 
finally: 
    #here is where cleanup is supposed to happen before raising error 
    break 
    #after finally code: raise error 

Da die Ansammlung von Fehlern geschieht nie in den finally Block es wird nie wirklich ausgelöst.

Um die Rückwärtskompatibilität mit den Python-Versionen 2.4 und weniger zu erhalten, musste dies auf diese Weise durchgeführt werden.

+1

Ok, also ist es dokumentiert. Aber ich muss sagen, dass ich dieses Verhalten immer noch als sehr überraschend empfinde (im Gegensatz zum meisten Python-Verhalten, das normalerweise so intuitiv ist). Mein Gefühl ist, dass Ausnahmen "Return" (s) oder Break (s) "trumpfen" sollten ... – TimO

+0

@TimO Ich stimme zu. Ich frage mich, ob das vielleicht nicht auf diese Weise implementiert wurde, weil sie das Verhalten von break für diesen bestimmten Blocktyp nicht überschreiben müssten. –

1

I denke, nach Reflexion, dass es aufgrund der Tatsache ist, dass Pause tatsächlich eine StopIteration auslöst, um aus der for-Schleife "zu brechen". Dies ist wirklich nicht sehr intuitiv und nicht besonders gut dokumentiert (zum Beispiel nicht erwähnt auf 1). Könnte vielleicht jemand es besser bestätigen/erklären?

+0

Ist das wirklich der Fall oder nur eine Vermutung? Wenn dies der Fall ist, kann ich dann die StopIteration-Ausnahme, die durch die Unterbrechung in der Schleife verursacht wurde, nicht abfangen? Auch das manuelle Auslösen einer StopIteration in einer for-Schleife hat denselben Effekt. –

+0

@tobias_k Es war ein - wahrscheinlich falsch - raten. Die Dokumentation erklärt es - siehe akzeptierte Antwort. – TimO

5

Aus der Dokumentation Error Handling Docs:

Ein finally-Klausel immer vor dem Verlassen der try-Anweisung ausgeführt wird, ob eine Ausnahme aufgetreten ist oder nicht.

Ihre Ausnahmebedingung wird nie ausgelöst, weil Sie vor der vollständigen Auswertung der try-Anweisung einen Abbruch vornehmen.

Verwandte Themen