Seltsames Try-Except-Else-finally-Verhalten mit Return-Anweisungen

87

Dies ist ein Code, der sich besonders verhält. Dies ist eine vereinfachte Version des Verhaltens, das ich geschrieben habe. Dies wird immer noch das seltsame Verhalten demonstrieren und ich hatte einige spezifische Fragen, warum dies geschieht.

Ich verwende Python 2.6.6 unter Windows 7.

def demo1():
    try:
        raise RuntimeError,"To Force Issue"
    except:
        return 1
    else:
        return 2
    finally:
        return 3

def demo2():
    try:
        try:
            raise RuntimeError,"To Force Issue"
        except:
            return 1
        else:
            return 2
        finally:
            return 3
    except:
        print 4
    else:
        print 5
    finally:
        print 6

Ergebnisse:

>>> print demo1()
3
>>> print demo2()
6
3
  • Warum gibt Demo 1 3 statt 1 zurück?
  • Warum druckt Demo 2 6 statt 6 mit 4 oder 5?
Kyle Owens
quelle

Antworten:

121

Weil finallyAnweisungen garantiert ausgeführt werden (vorausgesetzt, es liegt kein Stromausfall oder etwas außerhalb der Kontrolle von Python vor). Dies bedeutet, dass die Funktion, bevor sie zurückkehren kann, den finally-Block ausführen muss, der einen anderen Wert zurückgibt.

In den Python-Dokumenten heißt es :

Wenn eine return-, break- oder continue-Anweisung in der try-Suite einer try… finally-Anweisung ausgeführt wird, wird die finally-Klausel auch "auf dem Weg nach draußen" ausgeführt.

Der Rückgabewert einer Funktion wird durch die zuletzt ausgeführte Rückgabeanweisung bestimmt. Da die finally-Klausel immer ausgeführt wird, ist eine in der finally-Klausel ausgeführte return-Anweisung immer die zuletzt ausgeführte:

Dies bedeutet, dass beim Versuch, zurückzukehren, der finallyBlock aufgerufen wird und seinen Wert anstelle desjenigen zurückgibt, den Sie gehabt hätten.

Gareth Latty
quelle
4
Warum drucken die 5 nicht im zweiten Beispiel? das ist immer noch nicht gut erklärt, denke ich. Die Rückgabe ist gut beantwortet, aber warum druckt die 5 im zweiten Beispiel nicht
Joran Beasley
5
Oh, ich glaube, ich habe es herausgefunden. Die Rückkehr beim ersten Versuch führt dazu, dass es sofort nach außen springt
Joran Beasley
2
Genau, weil immerfinally Blöcke laufen.
Gareth Latty
2
Warum führt es in Demo zwei das verschachtelte endgültig aus, tritt schließlich nach außen aus und kehrt dann endgültig in das verschachtelte zurück, um die Rückgabe zu beenden, anstatt einfach keines von außen endgültig zurückzugeben?
Kyle Owens
1
Denn wenn die returnAnweisung aufgerufen wird, sucht Python nach offenen finallyKlauseln, die ausgeführt werden müssen (siehe obiges Zitat).
Gareth Latty
6

Die Ausführungsreihenfolge lautet:

  1. try block all wird normal abgeschlossen -> finally block -> Funktion endet
  2. versuche block run und komme in ausnahme A -> endlich block -> funktion endet
  3. try block macht einen Rückgabewert und ruft return auf -> finally block -> popup return value -> Funktion endet

Jede Rückkehr im finally-Block beendet die Schritte im Voraus.

Fred Huang
quelle