Warum verwendet Python 'else' nach for- und while-Schleifen?

480

Ich verstehe, wie dieses Konstrukt funktioniert:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

Aber ich verstehe nicht, warum elsehier als Schlüsselwort verwendet wird, da dies darauf hindeutet, dass der betreffende Code nur ausgeführt wird, wenn der forBlock nicht vollständig ist, was das Gegenteil von dem ist, was er tut! Egal wie ich darüber denke, mein Gehirn kann nicht nahtlos von der forAussage zum elseBlock übergehen. Für mich continueoder continuewithwürde mehr Sinn machen (und ich versuche mich zu trainieren, es als solches zu lesen).

Ich frage mich, wie Python-Codierer dieses Konstrukt in ihrem Kopf lesen (oder laut, wenn Sie möchten). Vielleicht fehlt mir etwas, das solche Codeblöcke leichter entzifferbar macht?

Kent Boogaart
quelle
26
Vielleicht möchten Sie es in Ihrem Kopf in "dann" übersetzen.
Marcin
63
Vergessen Sie nicht die Schlüsselzeile im Zen von Python: "... so ist es zunächst vielleicht nicht offensichtlich, es sei denn, Sie sind Holländer."
Daniel Roseman
50
In meinem Kopf übersetze ich es in "wenn nicht brechen" . Und da breakes in "Ich habe es gefunden" -Schleifen häufig verwendet wird, können Sie es in "Wenn nicht gefunden" übersetzen , was nicht weit von dem entfernt ist, was elselautet
MestreLion
29
Ich denke, die eigentliche Frage, die viele Leute hier haben, ist: "Was ist der Unterschied zwischen for ... else foo()und nur foo()nach der for-Schleife setzen?" Und die Antwort ist, dass sie sich nur dann anders verhalten, wenn die Schleife ein enthält break(wie unten ausführlich beschrieben).
Sam Kauffman
10
Ein Semikolon in Python ... meine Augen tun weh ... obwohl es syntaktisch korrekt ist, ist es keine gute Praxis, dies zu tun
DarkCygnus

Antworten:

278

Es ist ein seltsames Konstrukt, selbst für erfahrene Python-Codierer. In Verbindung mit for-Schleifen bedeutet dies im Grunde "Finde ein Element in der Iterable, sonst, wenn keines gefunden wurde, mache ...". Wie in:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

Immer wenn Sie dieses Konstrukt sehen, ist es eine bessere Alternative, die Suche entweder in eine Funktion zu kapseln:

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

Oder verwenden Sie ein Listenverständnis:

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

Es ist nicht semantisch äquivalent zu den beiden anderen Versionen, funktioniert jedoch in nicht leistungskritischem Code, bei dem es keine Rolle spielt, ob Sie die gesamte Liste durchlaufen oder nicht, gut genug. Andere mögen anderer Meinung sein, aber ich persönlich würde es vermeiden, jemals die for-else- oder while-else-Blöcke im Produktionscode zu verwenden.

Siehe auch [Python-Ideen] Zusammenfassung von für ... sonstige Threads

Björn Lindqvist
quelle
50
Das Listenverständnis ist der falsche Einzeiler. Wenn Sie wie in den forSchleifenbeispielen nach einem einzelnen Element suchen und einen Generatorausdruck / ein Listenverständnis verwenden möchten, möchten next((o for o in objects if o.key == search_key), None)oder wickeln Sie es in ein try/ exceptund verwenden keinen Standardwert anstelle eines if/ else.
Agf
4
und wie bei Lance Helsten gibt es tatsächlich Fälle, in denen es besser ist, ein for/elseKonstrukt zu verwenden.
andrean
5
Prost. Ich hatte eine schlecht eingerückte Datei, in der eine elsemit einer gepaart wurde, forund ich hatte keine Ahnung, dass dies legal war.
Maxywb
3
Ich denke, dass die for-Schleife das offensichtlichste der dortigen Konstrukte ist.
Miles Rout
14
Es ist erwähnenswert, dass die else-Klausel auch dann ausgeführt wird, wenn die for-Schleife Werte enthält, es sei denn, eine breakAnweisung wird explizit wie in diesem Beispiel ausgeführt. Aus den obigen Dokumenten: "Die elseKlausel hat ein anderes wahrgenommenes Problem: Wenn sich keine breakin der Schleife befindet, ist die elseKlausel funktional redundant." zBfor x in [1, 2, 3]:\n print x\n else:\n print 'this executes due to no break'
Dhackner
586

Ein übliches Konstrukt besteht darin, eine Schleife auszuführen, bis etwas gefunden ist, und dann aus der Schleife auszubrechen. Das Problem ist, dass ich feststellen muss, welcher Fall passiert ist, wenn ich aus der Schleife ausbreche oder die Schleife endet. Eine Methode besteht darin, ein Flag oder eine Speichervariable zu erstellen, mit der ich einen zweiten Test durchführen kann, um festzustellen, wie die Schleife beendet wurde.

Angenommen, ich muss eine Liste durchsuchen und jedes Element verarbeiten, bis ein Flag-Element gefunden wird, und dann die Verarbeitung beenden. Wenn das Flag-Element fehlt, muss eine Ausnahme ausgelöst werden.

Verwenden Sie das Python for... else-Konstrukt, das Sie haben

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

Vergleichen Sie dies mit einer Methode, die diesen syntaktischen Zucker nicht verwendet:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

Im ersten Fall raiseist das eng an die for-Schleife gebunden, mit der es arbeitet. Im zweiten Fall ist die Bindung nicht so stark und es können Fehler während der Wartung auftreten.

Lance Helsten
quelle
69
Dies erklärt es besser als die gewählte Antwort, bei der der Autor nicht wirklich versteht, worum es sonst geht!
Erikbwork
17
Ich muss sagen, dass dieser syntaktische Zucker die Zähne Ihres Projekts verrotten könnte. Dies würde kein Python: the good partsBuch machen.
Bootscodierer
1
Können Sie bestätigen, dass in Ihrem Beispiel process(i)dies für jeden Artikel mylistgenau vorher theflagund nicht für sich theflagselbst geschieht ? Ist es das, was beabsichtigt war?
bli
4
processwird für jedes Element ausgeführt i, das in der Liste vorhanden theflagist, bevor es erreicht wurde. Es wird nicht für Elemente in der Liste ausgeführt, nachdem es erreicht wurde theflag, und es wird nicht für ausgeführt theflag.
Lance Helsten
1
Die else-Anweisung wird auch ausgeführt, wenn die Iterable keine Elemente enthält
Lost Crotchet
173

Es gibt eine ausgezeichnete Präsentation von Raymond Hettinger mit dem Titel Transforming Code in Beautiful, Idiomatic Python , in der er kurz auf die Geschichte des for ... elseKonstrukts eingeht . Der relevante Abschnitt ist "Unterscheiden mehrerer Austrittspunkte in Schleifen" ab 15:50 Uhr und dauert etwa drei Minuten. Hier sind die Höhepunkte:

  • Das for ... elseKonstrukt wurde von Donald Knuth als Ersatz für bestimmte GOTOAnwendungsfälle entwickelt;
  • Die Wiederverwendung des elseSchlüsselworts machte Sinn, weil "es das ist, was Knuth benutzte, und die Leute wussten zu dieser Zeit, dass alle [ forAussagen] ein ifund GOTOdarunter eingebettet hatten , und sie erwarteten das else;"
  • Im Nachhinein hätte es "no break" (oder möglicherweise "nobreak") heißen sollen, und dann wäre es nicht verwirrend. *

Wenn die Frage lautet: "Warum ändern sie dieses Schlüsselwort nicht?" dann gab Cat Plus Plus wahrscheinlich die genaueste Antwort - zu diesem Zeitpunkt wäre es zu destruktiv für vorhandenen Code, um praktisch zu sein. Aber wenn die Frage, die Sie wirklich stellen, ist, warum sie überhaupt elsewiederverwendet wurde, dann schien es zu dieser Zeit anscheinend eine gute Idee zu sein.

Persönlich mag ich den Kompromiss, inline zu kommentieren # no break, wo immer elsedies auf einen Blick als innerhalb der Schleife liegend verwechselt werden könnte. Es ist ziemlich klar und prägnant. Diese Option wird in der Zusammenfassung, die Björn am Ende seiner Antwort verlinkt hat, kurz erwähnt :

Der Vollständigkeit halber sollte ich erwähnen, dass Programmierer, die diese Syntax möchten, sie bei einer geringfügigen Änderung der Syntax jetzt haben können:

for item in sequence:
    process(item)
else:  # no break
    suite

* Bonuszitat aus diesem Teil des Videos: "Genau wie wenn wir Lambda Makefunction nennen würden, würde niemand fragen: 'Was macht Lambda?'"

Luft
quelle
33

Weil sie kein neues Schlüsselwort in die Sprache einführen wollten. Jeder stiehlt eine Kennung und verursacht Abwärtskompatibilitätsprobleme. Daher ist dies normalerweise ein letzter Ausweg.

Cat Plus Plus
quelle
2
Scheint finallyin diesem Fall eine bessere Wahl gewesen zu sein. War das Schlüsselwort finally zum Zeitpunkt der Einführung dieses Konstrukts noch nicht vorhanden?
Ponkadoodle
26
@Wallacoloo finallyist nicht viel besser, da dies impliziert, dass der Block immer nach der Schleife ausgeführt wird, und dies ist auch nicht der Fall (da dies überflüssig wäre, wenn nur der Code nach der Schleife ausgeführt würde).
Cat Plus Plus
Es kann auch nicht sein, finallydass die else-Klausel auch ausgeführt wird, wenn continuesie in der for-Schleife verwendet wird - das ist möglicherweise viele Male und nicht nur am Ende.
Pepr
6
@pepr elseKlausel Ausführung wird nicht von betroffen continue( docs und Testcode )
Air
@ AirThomas: +1. Du hast recht. Das elsewird nur ausgeführt, wenn continuees das für die letzte Iteration war.
Pepr
33

Um es einfach zu machen, können Sie sich das so vorstellen.

  • Wenn es auf den breakBefehl in der forSchleife stößt , wird das elseTeil nicht aufgerufen.
  • Wenn der breakBefehl in der forSchleife nicht auftritt, wird das elseTeil aufgerufen.

Mit anderen Worten, wenn für die Schleifeniteration nicht mit "gebrochen" wird break, wird der elseTeil aufgerufen.

Ad infinitum
quelle
Der elseBlock wird auch nicht ausgeführt, wenn der Hauptteil der Schleife eine Ausnahme auslöst.
Amal K
17

Der einfachste Weg, um herauszufinden, was das for / else getan hat, und was noch wichtiger ist, wann ich es verwenden soll, war mich darauf zu konzentrieren, wohin die break-Anweisung springt. Das For / else-Konstrukt ist ein einzelner Block. Die Pause springt aus dem Block und springt so über die else-Klausel. Wenn der Inhalt der else-Klausel einfach der for-Klausel folgt, wird sie niemals übersprungen, und daher müsste die entsprechende Logik bereitgestellt werden, indem sie in ein if eingefügt wird. Dies wurde bereits gesagt, aber nicht ganz in diesen Worten, so dass es jemand anderem helfen kann. Versuchen Sie, das folgende Codefragment auszuführen. Ich bin aus Gründen der Klarheit von ganzem Herzen für den Kommentar "Keine Pause".

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')
Neil_UK
quelle
"Die Pause springt aus dem Block heraus und springt so 'über' die else-Klausel" - obwohl dies hilfreich sein kann, um for:/ zu "bekommen" else:, liefert es keine wirkliche Rechtfertigung für das Schlüsselwort Wesen else. Angesichts der hier gegebenen Rahmung then:scheint es viel natürlicher zu sein. (Es gibt Gründe für elsedie Auswahl, die in anderen Antworten angegeben sind - sie werden hier einfach nicht angegeben.)
Mark Amery
16

Ich denke, die Dokumentation hat eine großartige Erklärung für andere , fahren Sie fort

[...] wird ausgeführt, wenn die Schleife durch Erschöpfung der Liste (mit for) endet oder wenn die Bedingung (mit while) falsch wird, aber nicht, wenn die Schleife durch eine break-Anweisung beendet wird. "

Quelle: Python 2 docs: Tutorial zum Kontrollfluss

Ayan
quelle
13

Ich habe es so gelesen wie:

Wenn Sie immer noch die Voraussetzungen haben, um die Schleife auszuführen, tun Sie etwas , sonst etwas anderes.

pcalcao
quelle
Ihr noch auf den Bedingungen ist hilfreich (+1), obwohl es falsch ist - es ist menschlich ;-)
Wolf
-1; Diese Aussprache von for:/ else:lässt es so klingen, als würde der else:Wille immer nach der Schleife laufen, was nicht der Fall ist.
Mark Amery
11

Da der technische Teil ziemlich genau beantwortet wurde, bezieht sich mein Kommentar nur auf die Verwirrung , die dieses recycelte Schlüsselwort erzeugt.

Da Python eine sehr beredte Programmiersprache ist, ist der Missbrauch eines Schlüsselworts berüchtigter. Das elseSchlüsselwort beschreibt perfekt einen Teil des Ablaufs eines Entscheidungsbaums: "Wenn Sie dies nicht können, tun Sie das (sonst)". Es ist in unserer eigenen Sprache impliziert .

Stattdessen führt die Verwendung dieses Schlüsselworts mit whileund for-Anweisungen zu Verwirrung. Der Grund, unsere Karriere als Programmierer hat uns gelehrt, dass die elseAussage in einem Entscheidungsbaum liegt; sein logischer Bereich , ein Wrapper, der bedingt einen Pfad zurückgibt, dem er folgen soll. In der Zwischenzeit haben Schleifenanweisungen ein bildliches explizites Ziel, etwas zu erreichen. Das Ziel wird nach kontinuierlichen Iterationen eines Prozesses erreicht.

if / else Geben Sie einen Pfad an, dem Sie folgen möchten . Schleifen folgen einem Pfad, bis das "Ziel" erreicht ist .

Das Problem ist, dass dies elseein Wort ist, das die letzte Option in einer Bedingung klar definiert. Die Semantik des Wortes sind beide geteilt durch Python und menschliche Sprache. Das Wort else in der menschlichen Sprache wird jedoch niemals verwendet, um die Aktionen anzugeben, die jemand oder etwas ausführen wird, nachdem etwas abgeschlossen ist. Es wird verwendet, wenn während des Abschlusses ein Problem auftritt (eher wie eine break- Anweisung).

Am Ende bleibt das Schlüsselwort in Python. Es ist klar, dass es ein Fehler war, klarer, wenn jeder Programmierer versucht, eine Geschichte zu entwickeln, um seine Verwendung wie ein Gedächtnisgerät zu verstehen. Ich hätte es geliebt, wenn sie stattdessen das Schlüsselwort gewählt hätten then. Ich glaube, dass dieses Schlüsselwort perfekt in diesen iterativen Ablauf passt, die Auszahlung nach der Schleife.

Es ähnelt der Situation, die ein Kind hat, nachdem es jeden Schritt beim Zusammenbau eines Spielzeugs befolgt hat : Und DANN welcher Vater?

3rdWorldCitizen
quelle
Ich denke, dass diese Antwort das Problem der Verwirrung anspricht, über das das OP gesprochen hat. Das else-Schlüsselwort macht genau das Gegenteil von dem, was Sie von der englischen Bedeutung von else erwarten würden, wenn es an die Aktion von for angehängt wird. Theoretisch hätte das for ... else anders funktionieren können, da Sie im else-Teil landen, wenn die Schleife herausgebrochen ist. Das Problem ist jedoch, dass Sie es verwenden, um das Element x zu finden und den Fall zu behandeln, in dem x ist nicht gefunden, müssen Sie möglicherweise eine Flagge oder einen anderen Test nach dem Ganzen für .. sonst Konstrukt
Spacen Jasset
7

Ich las es wie iterablefolgt: "Wenn das vollständig erschöpft ist und die Ausführung nach Abschluss des Vorgangs mit der nächsten Anweisung fortfährt for, wird die else-Klausel ausgeführt." Wenn also die Iteration unterbrochen wird break, wird dies nicht ausgeführt.

0xc0de
quelle
6

Ich stimme zu, es ist eher wie ein "Elif nicht [Bedingung (en), die eine Pause einlegen]".

Ich weiß, dass dies ein alter Thread ist, aber ich beschäftige mich gerade mit derselben Frage, und ich bin nicht sicher, ob jemand die Antwort auf diese Frage so erfasst hat, wie ich sie verstehe.

Für mich gibt es drei Möglichkeiten, das elseIn For... elseoder die While... elseAnweisungen zu "lesen" , die alle gleichwertig sind:

  1. else == if the loop completes normally (without a break or error)
  2. else == if the loop does not encounter a break
  3. else == else not (condition raising break) (Vermutlich gibt es eine solche Bedingung, oder Sie hätten keine Schleife)

Im Wesentlichen ist das "else" in einer Schleife also wirklich ein "elif ...", wobei "..." (1) keine Unterbrechung ist, was (2) NICHT [Bedingung (en), die eine Unterbrechung auslösen] entspricht.

Ich denke, der Schlüssel ist, dass das elseohne die 'Pause' sinnlos ist, also for...elsebeinhaltet a:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

Die wesentlichen Elemente einer for...elseSchleife lauten also wie folgt, und Sie würden sie in einfacherem Englisch lesen als:

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

Wie auf den anderen Postern bereits erwähnt, wird in der Regel eine Unterbrechung ausgelöst, wenn Sie feststellen können, wonach Ihre Schleife sucht. Dies else:wird zu "Was tun, wenn das Zielobjekt nicht gefunden wird".

Beispiel

Sie können auch Ausnahmebehandlung, Unterbrechungen und for-Schleifen zusammen verwenden.

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

Ergebnis

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

Beispiel

Einfaches Beispiel mit einer Pause.

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

Ergebnis

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

Beispiel

Einfaches Beispiel, bei dem keine Unterbrechung, keine Bedingung, die eine Unterbrechung auslöst, und kein Fehler auftreten.

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

Ergebnis

z: 0
z: 1
z: 2
z_loop complete without break or error
----------
NotAnAmbiTurner
quelle
6

Das elseSchlüsselwort kann hier verwirrend sein, und so viele Menschen darauf hingewiesen haben, so etwas wie nobreak, notbreakist besser geeignet.

Um zu verstehen , for ... else ...logisch, vergleichen sie mit try...except...else, nicht if...else..., die meisten Python - Programmierer mit dem folgenden Code vertraut sind:

try:
    do_something()
except:
    print("Error happened.") # The try block threw an exception
else:
    print("Everything is find.") # The try block does things just find.

Stellen Sie sich das breakals eine besondere Art von vor Exception:

for x in iterable:
    do_something(x)
except break:
    pass # Implied by Python's loop semantics
else:
    print('no break encountered')  # No break statement was encountered

Der Unterschied ist pythonimpliziert except breakund Sie können es nicht ausschreiben, so wird es:

for x in iterable:
    do_something(x)
else:
    print('no break encountered')  # No break statement was encountered

Ja, ich weiß, dass dieser Vergleich schwierig und lästig sein kann, aber er verdeutlicht die Verwirrung.

Cizixs
quelle
Sie sollten beim Kopieren einen Link zur Ressource erstellen : Nick Coghlans Python Notes .
Godaygo
@godaygo danke für den Link. Ich habe das Konzept gelesen und akzeptiert, als ich Python zum ersten Mal lernte, und die Quelle beim Schreiben der Antwort nicht auswendig gelernt.
Cizixs
@cizixs Du hast "die Quelle nicht auswendig gelernt", aber zufällig ganze Sätze von Kommentaren aufgenommen, die mit dem Original identisch sind? Ooookaaaay.
Mark Amery
5

Codes im elseAnweisungsblock werden ausgeführt, wenn die forSchleife nicht unterbrochen wurde.

for x in xrange(1,5):
    if x == 5:
        print 'find 5'
        break
else:
    print 'can not find 5!'
#can not find 5!

Aus den Dokumenten: break and continue-Anweisungen und sonst Klauseln für Schleifen

Schleifenanweisungen können eine else-Klausel enthalten. Es wird ausgeführt, wenn die Schleife durch Erschöpfung der Liste (mit for) beendet wird oder wenn die Bedingung falsch wird (mit while), jedoch nicht, wenn die Schleife durch eine break-Anweisung beendet wird. Dies wird durch die folgende Schleife veranschaulicht, die nach Primzahlen sucht:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, 'equals', x, '*', n//x)
...             break
...     else:
...         # loop fell through without finding a factor
...         print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

(Ja, dies ist der richtige Code. Schauen Sie genau hin: Die else-Klausel gehört zur for-Schleife, nicht zur if-Anweisung.)

Bei Verwendung mit einer Schleife hat die else-Klausel mehr mit der else-Klausel einer try-Anweisung zu tun als mit der if-Anweisung: Die else-Klausel einer try-Anweisung wird ausgeführt, wenn keine Ausnahme auftritt, und die else-Klausel einer Schleife wird ausgeführt, wenn keine Unterbrechung auftritt . Weitere Informationen zu try-Anweisungen und Ausnahmen finden Sie unter Behandeln von Ausnahmen.

Die ebenfalls von C entliehene continue-Anweisung wird mit der nächsten Iteration der Schleife fortgesetzt:

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue
...     print("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9
Ich gehe meinen Weg
quelle
1
Dies fügt nichts hinzu und beantwortet die Frage nicht, was nicht wie, sondern warum ist .
Air
5

Hier ist eine Möglichkeit, darüber nachzudenken, die ich oben noch nicht erwähnt habe:

Denken Sie zunächst daran, dass for-Schleifen im Grunde nur syntaktischer Zucker um while-Schleifen sind. Zum Beispiel die Schleife

for item in sequence:
    do_something(item)

kann (ungefähr) umgeschrieben werden als

item = None
while sequence.hasnext():
    item = sequence.next()
    do_something(item)

Zweitens, denken Sie daran, dass while-Schleifen im Grunde nur if-Blöcke wiederholt werden! Sie können eine while-Schleife immer als "Wenn diese Bedingung erfüllt ist, führen Sie den Body aus und kehren Sie dann zurück und überprüfen Sie erneut".

Also, während / else vollkommen Sinn macht: Es ist genau die gleiche Struktur wie wenn / else, mit der zusätzlichen Funktionalität der Schleife, bis die Bedingung falsch wird, anstatt die Bedingung nur einmal zu überprüfen.

Und dann macht for / else auch vollkommen Sinn: Da alle for-Schleifen nur syntaktischer Zucker über while-Schleifen sind, müssen Sie nur herausfinden, was die implizite Bedingung der zugrunde liegenden while-Schleife ist, und dann entspricht das else dem Zeitpunkt Bedingung wird falsch.

Aaron Gable
quelle
4

Gute Antworten sind:

  • dies, was die Geschichte erklärt, und
  • Dies gibt das richtige Zitat, um Ihre Übersetzung / Ihr Verständnis zu erleichtern.

Meine Anmerkung hier stammt von dem, was Donald Knuth einmal gesagt hat (Entschuldigung, ich kann keinen Hinweis finden), dass es ein Konstrukt gibt, bei dem while-else nicht von if-else zu unterscheiden ist, nämlich (in Python):

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

hat den gleichen Durchfluss (ohne geringe Füllstandsunterschiede) wie:

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

Der Punkt ist, dass if-else als syntaktischer Zucker für while-else betrachtet werden kann, was breakam Ende seines ifBlocks impliziert ist . Die entgegengesetzte Implikation, auf die diese whileSchleife erweitert wird if, ist häufiger (es handelt sich lediglich um eine wiederholte / geloopte bedingte Prüfung), da sie ifhäufig zuvor gelehrt wird while. Dies ist jedoch nicht wahr, da dies bedeuten würde, dass elseblock-while-else jedes Mal ausgeführt wird, wenn die Bedingung falsch ist.

Um Ihr Verständnis zu erleichtern, denken Sie so:

Ohne break, returnetc., nur Schleifenenden , wenn die Bedingung ist nicht mehr wahr und in einem solchen Fall elseBlock wird ebenfalls einmal ausführen. Im Fall von Python formüssen Sie forSchleifen im C-Stil (mit Bedingungen) berücksichtigen oder in diese übersetzen while.

Noch ein Hinweis:

Vorzeitige break, returnetc. Looping macht unmöglich Bedingung falsch zu werden , weil die Ausführung der Schleife gesprungen, während die Bedingung wahr war und es würde nie wieder zu überprüfen.

WloHu
quelle
3

Man könnte es sich so vorstellen, elsewie im Rest der Sachen oder den anderen Sachen, die nicht in der Schleife gemacht wurden.

Jamylak
quelle
3
for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
else:
    print("Completed successfully")

"else" hier ist verrückt einfach, nur gemein

1, "wenn for clauseabgeschlossen ist"

for i in range(3):
    print(i)

    if i == 2:
        print("Too big - I'm giving up!")
        break;
if "for clause is completed":
    print("Completed successfully")

Es ist üblich, so lange Anweisungen wie "for-Klausel ist abgeschlossen" zu schreiben, damit sie "else" einführen.

else Hier ist ein Wenn in seiner Natur.

2, aber wie wäre es for clause is not run at all

In [331]: for i in range(0):
     ...:     print(i)
     ...: 
     ...:     if i == 9:
     ...:         print("Too big - I'm giving up!")
     ...:         break
     ...: else:
     ...:     print("Completed successfully")
     ...:     
Completed successfully

Die Aussage ist also eine logische Kombination:

if "for clause is completed" or "not run at all":
     do else stuff

oder sagen Sie es so:

if "for clause is not partially run":
    do else stuff

oder so:

if "for clause not encounter a break":
    do else stuff
Infinitesimalrechnung
quelle
sonst fungiert als "Transaktion" in SQL.
Kalkül
2

Hier ist neben der Suche ein weiterer idiomatischer Anwendungsfall. Angenommen, Sie möchten warten, bis eine Bedingung erfüllt ist, z. B. ein Port, der auf einem Remote-Server geöffnet ist, sowie eine Zeitüberschreitung. Dann könnten Sie ein while...elseKonstrukt wie folgt verwenden:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()
Jonathan Sudiaman
quelle
1

Ich habe nur versucht, es selbst wieder zu verstehen. Ich fand, dass das Folgende hilft!

• Stellen Sie sich das elseals mit dem ifInneren der Schleife gepaart vor (anstatt mit dem for) - wenn die Bedingung erfüllt ist, brechen Sie die Schleife, sonst tun Sie dies - außer es ist eines, das elsemit mehreren ifs gepaart ist !
• Wenn überhaupt keine ifs zufrieden waren, machen Sie das else.
• Die multiplen ifs können auch tatsächlich als if- elifs betrachtet werden!

Germaine Goh
quelle
-2

Ich halte die Struktur wie für (falls) Ein anderes B, und für (if) -else ist eine besondere if-else , grob . Es kann hilfreich sein, etwas anderes zu verstehen .

A und B werden höchstens einmal ausgeführt, was der if-else-Struktur entspricht.

for (if) kann als spezielles if betrachtet werden, das eine Schleife ausführt, um zu versuchen, die if-Bedingung zu erfüllen. Sobald die if- Bedingung erfüllt ist, A und break ; Sonst B.

Jie Zhang
quelle
-2

Python verwendet eine else after for- und while-Schleife, sodass etwas anderes passiert, wenn für die Schleife nichts gilt. Zum Beispiel:

test = 3
while test == 4:
     print("Hello")
else:
     print("Hi")

Die Ausgabe wäre immer wieder 'Hi' (wenn ich richtig bin).

Mrmongoose64
quelle