Sonst Klausel auf Python while-Anweisung

320

Ich habe festgestellt, dass der folgende Code in Python legal ist. Meine Frage ist warum? Gibt es einen bestimmten Grund?

n = 5
while n != 0:
    print n
    n -= 1
else:
    print "what the..."
Ivan
quelle
5
@detly: Das liegt daran, dass die meisten Leute dieses Konstrukt meiden. :) Ich glaube, Guido hat während des Py3k-Prozesses erwähnt, dass zumindest die Wahl des Wortes elsefür diese Verwendung eine bemerkenswert schlechte Idee war und dass sie nicht mehr davon machen würden.
Nicholas Knight
5
@Nicholas Knight - ja, obwohl es verlockend ist, wäre es wahrscheinlich etwas, das nur ich auf den ersten Blick verstanden habe. Jeder andere arme Kerl müsste sich die Sprachspezifikation ansehen oder in die Vergangenheit reisen und hier auf Staheeeeey eine Frage stellen ...
Detly
8
Die Idee hinter der Auswahl von 'else' ist, dass dieses Konstrukt angeblich oft in Verbindung mit einem 'if X: break' innerhalb der while-Schleife verwendet wird. Da die 'else'-Klausel ausgeführt wird, wenn wir nicht aus der Schleife ausbrechen, bildet sie eine Art' else 'zum' if '.
Jonathan Hartley
12
Sie sollten es umbenennen after:.
naught101

Antworten:

387

Die elseKlausel wird nur ausgeführt, wenn Ihre whileBedingung falsch wird. Wenn Sie breakdie Schleife verlassen oder eine Ausnahme ausgelöst wird, wird sie nicht ausgeführt.

Eine Möglichkeit, darüber nachzudenken, ist ein if / else-Konstrukt in Bezug auf die Bedingung:

if condition:
    handle_true()
else:
    handle_false()

ist analog zum Schleifenkonstrukt:

while condition:
    handle_true()
else:
    # condition is false now, handle and go on with the rest of the program
    handle_false()

Ein Beispiel könnte sein wie folgt:

while value < threshold:
    if not process_acceptable_value(value):
        # something went wrong, exit the loop; don't pass go, don't collect 200
        break
    value = update(value)
else:
    # value >= threshold; pass go, collect 200
    handle_threshold_reached()
ars
quelle
42
"Die else-Klausel wird nur ausgeführt, wenn Ihre while-Bedingung falsch wird." Der Wortlaut hier impliziert, dass Ihr while-Zustand von einem Zustand von wahr zu falsch wechselt und dann ausgeführt wird. Wenn das while jedoch niemals wahr ist, wird die else-Klausel trotzdem ausgeführt.
user597608
Pseudocode Korrigieren Sie mich also, wenn ich falsch liege, aber dies ist genau das Gleiche, while {} something außer dass das somethingübersprungen wird, wenn Sie breakin der whileSchleife sind.
Daniel Kaplan
2
Der vielleicht genaueste Pseudocode wäre: while (True) {if (cond) {handle_true (); } else {handle_false (); brechen; }}
VinGarcia
2
"Pass nicht, geh nicht, sammle 200", haha, jeder, der weiß, woher das kommt, hatte eine gute Kindheit
Stefan Octavian
102

Die elseKlausel wird ausgeführt, wenn Sie einen Block normal verlassen, indem Sie die Schleifenbedingung treffen oder vom Boden eines try-Blocks fallen. Es wird nicht ausgeführt, wenn Sie breakoder returnaußerhalb eines Blocks oder eine Ausnahme auslösen. Es funktioniert nicht nur für while- und for-Schleifen, sondern auch für Try-Blöcke.

Sie finden es normalerweise an Stellen, an denen Sie normalerweise eine Schleife vorzeitig verlassen, und das Ablaufen am Ende der Schleife ist eine unerwartete / ungewöhnliche Gelegenheit. Wenn Sie beispielsweise eine Liste durchlaufen und nach einem Wert suchen:

for value in values:
    if value == 5:
        print "Found it!"
        break
else:
    print "Nowhere to be found. :-("
John Kugelman
quelle
1
Eigentlich ein ziemlich nützliches Konstrukt für so etwas. Ich weiß nicht, wie oft ich found_it=Falseam Anfang einer Schleife gesetzt habe und dann found_itam Ende einen If-Check durchführe
Cruncher
42

Als Antwort auf Is there a specific reason?hier ist eine interessante Anwendung: Ausbrechen mehrerer Schleifenebenen.

So funktioniert es: Die äußere Schleife hat am Ende eine Unterbrechung, sodass sie nur einmal ausgeführt wird. Wenn die innere Schleife jedoch abgeschlossen ist (keinen Divisor findet), erreicht sie die else-Anweisung und die äußere Unterbrechung wird nie erreicht. Auf diese Weise bricht ein Bruch in der inneren Schleife aus beiden Schleifen heraus und nicht nur aus einer.

for k in [2, 3, 5, 7, 11, 13, 17, 25]:
    for m in range(2, 10):
        if k == m:
            continue
        print 'trying %s %% %s' % (k, m)
        if k % m == 0:
            print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
            break
    else:
        continue
    print 'breaking another level of loop'
    break
else:
    print 'no divisor could be found!'

Für beide whileund forSchleifen wird die elseAnweisung am Ende ausgeführt, sofern breaksie nicht verwendet wurde.

In den meisten Fällen gibt es bessere Möglichkeiten, dies zu tun (in eine Funktion einbinden oder eine Ausnahme auslösen), aber das funktioniert!

Kennzeichen
quelle
1
Ich habe nicht abgelehnt, aber ich glaube, ich weiß, warum es jemand getan hat. Sie beantworten die Frage nicht und geben 14 Codezeilen mit nur 2 Beschreibungszeilen an. Wenn es eine Relevanz für die gestellte Frage gibt, sagen Sie es uns nicht ...
BlueEel
1
@ BlueEel danke für das Feedback! Ich habe mehr Erklärungen zum Code hinzugefügt und klarer gemacht, wie dies die Frage beantwortet (weil es einen Teil davon beantwortet).
Mark
Sie haben es geschafft, Ihren Code in einen Kontext zu setzen, und obwohl Sie nicht alle Fragen beantworten, sehe ich jetzt die Relevanz. Ich habe Ihre Antwort positiv bewertet, da sie jetzt für Neulinge und Anfänger (wie ich in Bezug auf Python) nützlich ist. - Danke, ich habe etwas gelernt.
BlueEel
Ich mag die einfache Anwendung - jetzt sehe ich, warum jemand sie verwenden könnte. Obwohl ich nie einen Bedarf dafür gesehen habe.
gabe
Das Beispiel zeigt die Verwendung von for / else, aber die Frage betraf speziell while / else.
Ian Goldby
20

Die else-Klausel wird ausgeführt, wenn die while-Bedingung false ergibt.

Aus der Dokumentation :

Die while-Anweisung wird für die wiederholte Ausführung verwendet, solange ein Ausdruck wahr ist:

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

Dadurch wird der Ausdruck wiederholt getestet und, falls dies zutrifft, die erste Suite ausgeführt. Wenn der Ausdruck falsch ist (was möglicherweise das erste Mal ist, dass er getestet wird), wird die Suite der elseKlausel, falls vorhanden, ausgeführt und die Schleife wird beendet.

Eine breakin der ersten Suite ausgeführte Anweisung beendet die Schleife, ohne die elseSuite der Klausel auszuführen . Eine continuein der ersten Suite ausgeführte Anweisung überspringt den Rest der Suite und geht zurück zum Testen des Ausdrucks.

Mark Rushakoff
quelle
15

Meine Antwort wird sich darauf konzentrieren, WANN wir while / for-else verwenden können.

Auf den ersten Blick scheint es bei der Verwendung keinen Unterschied zu geben

while CONDITION:
    EXPRESSIONS
print 'ELSE'
print 'The next statement'

und

while CONDITION:
    EXPRESSIONS
else:
    print 'ELSE'
print 'The next statement'

Weil die print 'ELSE'Anweisung in beiden Fällen immer ausgeführt zu sein scheint (sowohl wenn die whileSchleife beendet ist als auch nicht).

Dann ist es nur anders, wenn die Anweisung print 'ELSE'nicht ausgeführt wird. Es ist, wenn sich breakinnerhalb des Codeblocks ein befindetwhile

In [17]: i = 0

In [18]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
else:
    print 'ELSE'
print 'The next statement'
   ....:
0
1
2
The next statement

Wenn abweichend von:

In [19]: i = 0

In [20]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
print 'ELSE'
print 'The next statement'
   ....:
0
1
2
ELSE
The next statement

return ist nicht in dieser Kategorie, da es in zwei oben genannten Fällen den gleichen Effekt hat.

Ausnahmeerhöhung verursacht auch keinen Unterschied, da beim Auslösen, wo der nächste Code ausgeführt wird, der Ausnahmebehandlungsroutine (außer Block), der Code in elseKlausel oder direkt nach der whileKlausel nicht ausgeführt wird.

HVNSweeting
quelle
4

Ich weiß, das ist eine alte Frage, aber ...

Wie Raymond Hettinger sagte, sollte es statt genannt while/no_breakwerden while/else.
Ich finde es leicht zu verstehen, wenn Sie sich diesen Ausschnitt ansehen.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
if n == 0:
    print n

Anstatt jetzt die Bedingung nach der while-Schleife zu überprüfen, können wir sie austauschen elseund diese Prüfung loswerden.

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
else:  # read it as "no_break"
    print n

Ich habe es immer als gelesen while/no_break , um den Code zu verstehen, und diese Syntax ist für mich viel sinnvoller.

Iluvatar
quelle
3

Die else-Klausel wird nur ausgeführt, wenn die while-Bedingung erfüllt ist falsch wird.

Hier sind einige Beispiele:

Beispiel 1: Anfangs ist die Bedingung falsch, daher wird die else-Klausel ausgeführt.

i = 99999999

while i < 5:
    print(i)
    i += 1
else:
    print('this')

AUSGABE:

this

Beispiel 2: Die while-Bedingung wurde i < 5 nie falsch, da i == 3die Schleife unterbrochen wird und die else-Klausel nicht ausgeführt wurde.

i = 0

while i < 5:
    print(i)
    if i == 3:
        break
    i += 1
else:
    print('this')

AUSGABE:

0
1
2
3

Beispiel 3: Die while-Bedingung i < 5 wurde falsch, als was iwar 5, also wurde die else-Klausel ausgeführt.

i = 0

while i < 5:
    print(i)
    i += 1
else:
    print('this')

AUSGABE:

0
1
2
3
4
this
Saif Ur Rahman
quelle
0

Die else:Anweisung wird nur dann ausgeführt, wenn die while-Schleife ihre Bedingung nicht mehr erfüllt (in Ihrem Beispiel, wenn sie n != 0falsch ist).

Die Ausgabe wäre also:

5
4
3
2
1
what the...
BoltClock
quelle
Ich weiß, aber diese Art von while / else funktioniert nicht in Java. Ich finde es ziemlich interessant, als ich herausfand, dass es in Python funktioniert. Ich war nur neugierig und wollte den technischen Grund wissen.
Ivan
6
@Ivan: Es ist nicht so sehr, dass es in Java nicht funktioniert, sondern dass es in Java nicht existiert . Es könnte funktionieren, wenn jemand daran interessiert wäre, es der Sprache hinzuzufügen.
Ignacio Vazquez-Abrams
1
Nein, während False: .. else .. noch die else-Klausel ausführt. Es ist genauer zu sagen: Sonst wird nur nicht ausgeführt, wenn die Schleife unterbrochen ist.
Leo Ufimtsev
0

Andernfalls wird ausgeführt, wenn die while-Schleife nicht unterbrochen wurde.

Ich denke gerne mit einer "Läufer" -Metapher darüber nach.

Das "Sonst" ist wie das Überqueren der Ziellinie, unabhängig davon, ob Sie am Anfang oder am Ende der Strecke begonnen haben. "else" wird nur nicht ausgeführt, wenn Sie irgendwo dazwischen brechen.

runner_at = 0 # or 10 makes no difference, if unlucky_sector is not 0-10
unlucky_sector = 6
while runner_at < 10:
    print("Runner at: ", runner_at)
    if runner_at == unlucky_sector:
        print("Runner fell and broke his foot. Will not reach finish.")
        break
    runner_at += 1
else:
    print("Runner has finished the race!") # Not executed if runner broke his foot.

Hauptanwendungsfälle sind das Ausbrechen verschachtelter Schleifen oder wenn Sie einige Anweisungen nur ausführen möchten, wenn die Schleife nicht irgendwo unterbrochen wurde (denken Sie daran, dass das Unterbrechen eine ungewöhnliche Situation ist).

Im Folgenden finden Sie beispielsweise einen Mechanismus zum Ausbrechen einer inneren Schleife ohne Verwendung von Variablen oder Try / Catch:

for i in [1,2,3]:
    for j in ['a', 'unlucky', 'c']:
        print(i, j)
        if j == 'unlucky':
            break
    else: 
        continue  # Only executed if inner loop didn't break.
    break         # This is only reached if inner loop 'breaked' out since continue didn't run. 

print("Finished")
# 1 a
# 1 b
# Finished
Leo Ufimtsev
quelle
-1

Die bessere Verwendung der Konstruktion 'while: else:' in Python sollte sein, wenn in 'while' keine Schleife ausgeführt wird, wird die Anweisung 'else' ausgeführt. Die heutige Funktionsweise macht keinen Sinn, da Sie den folgenden Code mit denselben Ergebnissen verwenden können ...

n = 5
while n != 0:
    print n
    n -= 1
print "what the..."
Jean Ferri
quelle
8
Nein, der Unterschied besteht darin, dass der elseBlock nicht ausgeführt wird, wenn Sie die Schleife mit dem Schlüsselwort breakoder verlassen return. In Ihrem Beispiel printwird auch ausgeführt, wenn die Schleife auf breakBefehl beendet wurde.
notsurewhattodo
2
Sie beschreiben, wie die meisten Leute wünschen, dass die Funktion funktioniert, nicht wie sie tatsächlich funktioniert!
Dotancohen
-2

Es ist nützlich für die soziale Interaktion.

while (Date != "January 1st"):
    time.sleep(1)
else:
    print("Happy new year!")
Guimoute
quelle
2
Und was genau ist der Zweck des elseHier? Der Code macht genau das gleiche ohne ihn.
Wovano
Wenn Ihre Uhr und Ihr Kalender breakwährend Ihres Countdowns nicht verwendet elsewerden, sagen Sie "Frohes neues Jahr!" sofort, was keinen Sinn ergibt.
Guimoute
@ Guimote, was meinst du mit "wenn deine Uhr und dein Kalender break"? breakDer Code enthält keine .
Wovano