Viele Python-Programmierer wissen wahrscheinlich nicht, dass die Syntax von while
Schleifen und for
Schleifen eine optionale else:
Klausel enthält:
for val in iterable:
do_something(val)
else:
clean_up()
Der Hauptteil der else
Klausel ist ein guter Ort für bestimmte Arten von Bereinigungsaktionen und wird bei normaler Beendigung der Schleife ausgeführt: Dh Verlassen der Schleife mit return
oder break
Überspringen der else
Klausel; Beenden nach einem continue
führt es aus. Ich weiß das nur, weil ich es gerade (noch einmal) nachgeschlagen habe , weil ich mich nie erinnern kann, wann die else
Klausel ausgeführt wird.
Immer? Bei "Ausfall" der Schleife, wie der Name schon sagt? Bei regelmäßiger Kündigung? Auch wenn die Schleife mit beendet wird return
? Ich kann nie ganz sicher sein, ohne es nachzuschlagen.
Ich beschuldige meine anhaltende Unsicherheit mit der Wahl des Schlüsselworts: Ich finde else
diese Semantik unglaublich unmnemonisch. Meine Frage lautet nicht "Warum wird dieses Schlüsselwort für diesen Zweck verwendet" (für das ich wahrscheinlich stimmen würde, wenn auch nur nach dem Lesen der Antworten und Kommentare), sondern wie kann ich über das else
Schlüsselwort nachdenken, damit seine Semantik Sinn macht, und ich kann mich also daran erinnern?
Ich bin mir sicher, dass darüber ziemlich viel diskutiert wurde, und ich kann mir vorstellen, dass die Wahl aus Gründen der Übereinstimmung mit der Klausel der try
Erklärung else:
(die ich auch nachschlagen muss) und mit dem Ziel getroffen wurde, nicht zur Liste von hinzuzufügen Pythons reservierte Worte. Vielleicht else
klären die Gründe für die Wahl seine Funktion und machen es einprägsamer, aber ich bin, nachdem ich den Namen mit der Funktion verbunden habe, nicht nach der historischen Erklärung an sich.
Die Antworten auf diese Frage , deren Frage kurz als Duplikat geschlossen wurde, enthalten viele interessante Hintergrundgeschichten. Meine Frage hat einen anderen Schwerpunkt (wie man die spezifische Semantik von else
mit der Keyword-Auswahl verbindet), aber ich denke, es sollte irgendwo einen Link zu dieser Frage geben.
quelle
else
bedeutet im Grunde "wenn die Fortsetzungsbedingung fehlschlägt". In einer traditionellen for-Schleife ist die Fortsetzungsbedingung normalerweisei < 42
. In diesem Fall können Sie diesen Teil alsif i < 42; execute the loop body; else; do that other thing
break
. Der kanonische Anwendungsfall ist, wenn die Schleife nach etwas sucht und bricht, wenn sie es findet. Daselse
wird nur ausgeführt, wenn nichts gefunden wird.Antworten:
(Dies ist inspiriert von der Antwort von @Mark Tolonen.)
Eine
if
Anweisung führt ihreelse
Klausel aus, wenn ihre Bedingung false ergibt. Identisch führt einewhile
Schleife die else-Klausel aus, wenn ihre Bedingung false ergibt.Diese Regel entspricht dem von Ihnen beschriebenen Verhalten:
break
Anweisung ausführen , verlassen Sie die Schleife, ohne die Bedingung auszuwerten, sodass die Bedingung nicht als falsch ausgewertet werden kann und Sie die else-Klausel niemals ausführen.continue
Anweisung ausführen , bewerten Sie die Bedingung erneut und tun genau das, was Sie normalerweise zu Beginn einer Schleifeniteration tun würden. Wenn die Bedingung wahr ist, führen Sie eine Schleife durch, aber wenn sie falsch ist, führen Sie die else-Klausel aus.return
, bewerten die Bedingung nicht und führen daher die else-Klausel nicht aus.for
Schleifen verhalten sich genauso. Betrachten Sie die Bedingung einfach als wahr, wenn der Iterator mehr Elemente enthält, oder andernfalls als falsch.quelle
elif
Aussagen. Es gibt eine Antwort , die dies tut, und es gibt eine Netto-Gegenstimme.break
In diesem Fallelse
würde das nicht ausgeführt, aber die Bedingung ist False. Ähnlich kann es mitfor
Schleifenbreak
auf dem letzten Element sein.Stellen Sie sich das besser so vor: Der
else
Block wird immer ausgeführt, wenn im vorhergehenden Block alles richtig läuftfor
, so dass er erschöpft ist.Richtig in diesem Zusammenhang bedeutet nein
exception
, neinbreak
, neinreturn
. Jede Anweisung, von der aus die Kontrolle übernommenfor
wird, führt dazu, dass derelse
Block umgangen wird.Ein häufiger Anwendungsfall wird bei der Suche nach einem Artikel in einem gefunden
iterable
, für den die Suche entweder abgebrochen wird, wenn der Artikel gefunden wird, oder eine"not found"
Flagge über den folgendenelse
Block gehisst / gedruckt wird :A
continue
entführt die Kontrolle nicht vonfor
, so dass die Kontrolleelse
nach demfor
Erschöpfen der fortgesetzt wird.quelle
else
Klausel ausgeführt wird, wenn die Dinge nicht richtig laufen, nicht wahr? Ich bin schon wieder verwirrt ...else
]" widersprechen , da das ausgeführtelse
wird, wenn keine der Bedingungen in der for-Schleife als wahr ausgewertet wird, wie ich in meiner AntwortFalse
. So ist die Frage, wie dasfor
ist gebrochen , hängt vom Anwendungsfall.else
in Python widerspiegelt ). Sie bieten eine gute intuitive Zusammenfassung dessenelse
, was @Moses tut, aber nicht, wie wir dieses Verhalten mit "else" verknüpfen könnten. Wenn ein anderes Schlüsselwort verwendet würde (z. B.nobreak
wie in dieser Antwort auf eine verwandte Frage erwähnt), wäre es einfacher, einen Sinn zu finden.if
/ alswhile
falsch ausgewertet wird oderfor
keine Elemente mehr vorhanden sind.break
existiert die enthaltende Schleife (nach demelse
).continue
geht zurück und wertet den Schleifenzustand erneut aus.Wann führt ein
if
einelse
? Wenn sein Zustand falsch ist. Es ist genau das gleiche für daswhile
/else
. Sie können sich alsowhile
/else
als nur eineif
vorstellen, die ihren wahren Zustand so lange beibehält, bis sie als falsch ausgewertet wird. Abreak
ändert das nicht. Es springt einfach ohne Auswertung aus der enthaltenen Schleife. Daselse
wird nur ausgeführt, wenn die Auswertung derif
/while
Bedingung falsch ist.Das
for
ist ähnlich, außer dass sein falscher Zustand seinen Iterator erschöpft.continue
undbreak
nicht ausführenelse
. Das ist nicht ihre Funktion. Das beendetbreak
die enthaltende Schleife. Dascontinue
geht zurück zum Anfang der enthaltenden Schleife, wo die Schleifenbedingung ausgewertet wird. Es ist der Akt der Bewertungif
/while
falsch (oderfor
hat keine Elemente mehr), der ausgeführt wirdelse
und keine andere Möglichkeit.quelle
else
Klausel ausgeführt wird, wenn die Schleife mitcontinue
(oder normalerweise) beendet wird, aber nicht wenn wir mit verlassenbreak
. Diese Feinheiten sind der Grund, warum ich wirklich versuche zu verstehen, waselse
fängt und was nicht.Dies ist, was es im Wesentlichen bedeutet:
Es ist eine schönere Art, dieses gemeinsame Muster zu schreiben:
Die
else
Klausel wird nicht ausgeführt, wenn es einreturn
weil gibt,return
das die Funktion verlässt, wie es beabsichtigt ist. Die einzige Ausnahme zu dem, an das Sie vielleicht denkenfinally
, ist, dass sichergestellt werden soll, dass es immer ausgeführt wird.continue
hat damit nichts besonderes zu tun. Dadurch wird die aktuelle Iteration der Schleife beendet, wodurch möglicherweise die gesamte Schleife beendet wirdbreak
. In diesem Fall wurde die Schleife eindeutig nicht durch a beendet .try/else
ist ähnlich:quelle
Wenn Sie sich Ihre Schleifen als eine ähnliche Struktur vorstellen (etwas Pseudocode):
es könnte ein bisschen sinnvoller sein. Eine Schleife ist im Wesentlichen nur eine
if
Anweisung, die wiederholt wird, bis die Bedingung erfüllt istfalse
. Und das ist der wichtige Punkt. Die Schleife überprüft ihren Zustand und stellt fest, dass dies derfalse
Fall ist , führt also dieelse
(genau wie eine normaleif/else
) aus und dann ist die Schleife fertig.Beachten Sie also, dass der
else
einzige get ausgeführt wird, wenn die Bedingung überprüft wird . Das heißt, wenn Sie den Hauptteil der Schleife während der Ausführung mit beispielsweise areturn
oder a verlassenbreak
, wird derelse
Fall nicht ausgeführt , da die Bedingung nicht erneut überprüft wird.A
continue
hingegen stoppt die aktuelle Ausführung und springt dann zurück, um den Zustand der Schleife erneut zu überprüfen, weshalb derelse
in diesem Szenario erreicht werden kann.quelle
end
Etikett weg und stecken Sie es einfachgoto loop
in denif
Körper. Vielleicht sogar übertroffen, indem man dasif
in die gleiche Zeile wie das Etikett setzt, und es sieht plötzlich sehr nach dem Original aus.Mein Gotcha-Moment mit der
else
Klausel der Schleife war, als ich einen Vortrag von Raymond Hettinger sah , der eine Geschichte darüber erzählte, wie er dachte, dass er hätte heißen sollennobreak
. Schauen Sie sich den folgenden Code an. Was würde er Ihrer Meinung nach tun?Was würden Sie vermuten, dass es tut? Nun, der Teil, der sagt,
nobreak
würde nur ausgeführt, wenn einebreak
Anweisung nicht in der Schleife getroffen würde.quelle
Normalerweise denke ich an eine Schleifenstruktur wie diese:
Um einer variablen Anzahl von
if/elif
Anweisungen sehr ähnlich zu sein :In diesem Fall
else
funktioniert die Anweisung in der for-Schleife genau wie dieelse
Anweisung in der Kette vonelif
s. Sie wird nur ausgeführt, wenn keine der Bedingungen zuvor als True ausgewertet wurde. (oder Unterbrechung der Ausführung mitreturn
oder mit einer Ausnahme) Wenn meine Schleife normalerweise nicht dieser Spezifikation entspricht, verzichte ich ausfor: else
genau dem Grund, aus dem Sie diese Frage gestellt haben, auf die Verwendung: Sie ist nicht intuitiv.quelle
Andere haben bereits die Mechanik von erklärt
while/for...else
, und die Python 3-Sprachreferenz hat die maßgebliche Definition (siehe while und for ), aber hier ist meine persönliche Mnemonik, FWIW. Ich denke, der Schlüssel für mich war, dies in zwei Teile zu unterteilen: einen zum Verständnis der Bedeutung derelse
in Bezug auf die Schleifenbedingung und einen zum Verständnis der Schleifensteuerung.Ich finde es am einfachsten, zunächst zu verstehen
while...else
:Die
for...else
Mnemonik ist im Grunde die gleiche:In beiden Fällen wird das
else
Teil erst erreicht, wenn keine weiteren Elemente mehr zu verarbeiten sind und das letzte Element regelmäßig verarbeitet wurde (dh neinbreak
oderreturn
). Acontinue
geht einfach zurück und sieht nach, ob es noch weitere Gegenstände gibt. Meine Mnemonik für diese Regeln gilt für beidewhile
undfor
:- mit „Schleife zurück zum Anfang“ , das heißt, natürlich, der Anfang der Schleife , wo wir prüfen , ob es noch weitere Elemente in der iterable sind, so weit das
else
geht,continue
spielt wirklich keine Rolle überhaupt.quelle
else
könnte auch verwendet werden, um etwas zu tun, wenn Sie einfach mit allen Gegenständen fertig sind. Beispiele hierfür sind das Schreiben eines Protokolleintrags, das Aktualisieren einer Benutzeroberfläche oder das Signalisieren eines anderen Prozesses, dass Sie fertig sind. Eigentlich alles. Außerdem haben einige Codeteile das "erfolgreiche" Fallende mit einem "break
innerhalb der Schleife", und daselse
wird verwendet, um den "Fehler" -Fall zu behandeln, bei dem Sie während der Iteration kein geeignetes Element gefunden haben (vielleicht haben Sie das gedacht von?).else
Block der Schleife einfügen oder das Ergebnis auf andere Weise verfolgen. Grundsätzlich stimme ich zu, ich sage nur, dass ich nicht weiß, wie Benutzer diese Funktion verwenden, und daher möchte ich vermeiden, Annahmen darüber zu treffen, ob daselse
Szenario " Behandelt einen erfolgreichen Fall" oder das Szenario "else
Behandelt einen nicht erfolgreichen Fall" häufiger vorkommt. Aber Sie haben einen guten Punkt, also Kommentar positiv bewertet!In der testgetriebenen Entwicklung (TDD) behandeln Sie Schleifen bei Verwendung des Paradigmas der Transformationsprioritätsprämisse als Verallgemeinerung von bedingten Anweisungen.
Dieser Ansatz lässt sich gut mit dieser Syntax kombinieren, wenn Sie nur einfache
if/else
(keineelif
) Anweisungen berücksichtigen :verallgemeinert auf:
schön.
In anderen Sprachen erfordern TDD-Schritte von einem Einzelfall zu Fällen mit Sammlungen mehr Refactoring.
Hier ist ein Beispiel aus dem 8thlight-Blog :
In dem verlinkten Artikel im 8thlight-Blog wird die Word Wrap-Kata berücksichtigt: Hinzufügen von Zeilenumbrüchen zu Zeichenfolgen (die
s
Variable in den folgenden Snippets), damit sie auf eine bestimmte Breite passen (dielength
Variable in den folgenden Snippets). An einem Punkt sieht die Implementierung wie folgt aus (Java):und der nächste Test, der derzeit fehlschlägt, ist:
Wir haben also Code, der bedingt funktioniert: Wenn eine bestimmte Bedingung erfüllt ist, wird ein Zeilenumbruch hinzugefügt. Wir möchten den Code verbessern, um mehrere Zeilenumbrüche zu verarbeiten. Die im Artikel vorgestellte Lösung schlägt vor, die Transformation (if-> while) anzuwenden. Der Autor gibt jedoch einen Kommentar ab, der Folgendes enthält :
Dies zwingt dazu, im Rahmen eines fehlgeschlagenen Tests weitere Änderungen am Code vorzunehmen:
In TDD möchten wir so wenig Code wie möglich schreiben, damit die Tests bestanden werden. Dank der Python-Syntax ist folgende Transformation möglich:
von:
zu:
quelle
So wie ich es sehe,
else:
wird ausgelöst , wenn Sie über das Ende der Schleife hinaus iterieren.Wenn Sie
break
oderreturn
oderraise
Sie nicht über das Ende der Schleife hinaus iterieren, stoppen Sie sofort und derelse:
Block wird daher nicht ausgeführt. Wenn Siecontinue
immer noch über das Ende der Schleife iterieren, springen Sie einfach mit der nächsten Iteration fort. Es stoppt die Schleife nicht.quelle
goto
der Erfolg oben steht.) Aber es ist eine kürzere Version der Antwort mit der höchsten Abstimmung ...Stellen Sie sich die
else
Klausel als Teil des Schleifenkonstrukts vor.break
bricht vollständig aus dem Schleifenkonstrukt aus und überspringt somit dieelse
Klausel.Aber wirklich, meine mentale Zuordnung ist einfach, dass es die 'strukturierte' Version des Musters C / C ++ ist:
Wenn ich
for...else
es also selbst begegne oder schreibe, anstatt es direkt zu verstehen , übersetze ich es mental in das obige Verständnis des Musters und erarbeite dann, welche Teile der Python-Syntax welchen Teilen des Musters zugeordnet sind.(Ich setze 'strukturiert' in Angstzitate, weil der Unterschied nicht darin besteht, ob der Code strukturiert oder unstrukturiert ist, sondern lediglich darin, ob der jeweiligen Struktur Schlüsselwörter und Grammatik zugeordnet sind.)
quelle
else
? Wenn Sie meinten, dasdone:
Etikett soll Proxy stehen oderelse:
ich glaube, Sie haben es genau rückwärts.done:
Etikett ausfüllen . Die Gesamtkorrespondenz lässt sich vielleicht am besten so sagen: Python hat daselse
Konstrukt -on-loop, mit dem Sie dieses Kontrollflussmuster ohne ausdrücken könnengoto
.else
vermeidet das.Wenn Sie paaren
else
mitfor
, könnte es verwirrend sein. Ich denke nicht, dass das Schlüsselwortelse
eine gute Wahl für diese Syntax war, aber wenn Sieelse
mitif
dem enthaltenenbreak
kombinieren, können Sie sehen, dass es tatsächlich Sinn macht.else
ist kaum nützlich, wenn es keine vorhergehendeif
Aussage gibt, und ich glaube, deshalb hat der Syntaxdesigner das Schlüsselwort gewählt.Lassen Sie es mich in menschlicher Sprache demonstrieren.
quelle
Die Art und Weise, wie ich darüber denke, ist der Schlüssel,
continue
eher die Bedeutung von als zu berücksichtigenelse
.Die anderen Schlüsselwörter, die Sie erwähnen, brechen aus der Schleife aus (beenden ungewöhnlich), während
continue
dies nicht der Fall ist. Sie überspringen lediglich den Rest des Codeblocks innerhalb der Schleife. Die Tatsache, dass es der Schleifenbeendigung vorausgehen kann, ist zufällig: Die Beendigung erfolgt tatsächlich auf normale Weise durch Auswertung des bedingten Schleifenausdrucks.Dann müssen Sie nur noch daran denken, dass die
else
Klausel nach der normalen Schleifenbeendigung ausgeführt wird.quelle
quelle