Else clause sur Python tandis que l'instruction

321

J'ai remarqué que le code suivant est légal en Python. Ma question est pourquoi? Y a-t-il une raison précise?

n = 5
while n != 0:
    print n
    n -= 1
else:
    print "what the..."
Ivan
la source
5
@detly: C'est parce que la plupart des gens évitent cette construction. :) Je crois que Guido a mentionné au cours du processus Py3k que, à tout le moins, le choix du mot elsepour cette utilisation avait été une très mauvaise idée, et qu'ils ne feraient plus cela.
Nicholas Knight
5
@Nicholas Knight - oui, si tentant que ce soit, ce serait probablement quelque chose que j'ai compris au premier coup d'œil. Toute autre sève pauvre devrait aller voir les spécifications de la langue, ou remonter le temps et poser une question ici sur Staheeeey ...
Detly
8
L'idée derrière le choix de 'else' est que cette construction est censée être souvent utilisée en conjonction avec un 'if X: break' à l'intérieur de la boucle while. Puisque la clause «else» est exécutée si nous ne sortons pas de la boucle, elle forme un «sorta» un peu à «if».
Jonathan Hartley
12
Ils devraient le renommer after:.
naught101

Réponses:

388

La elseclause n'est exécutée que lorsque votre whilecondition devient fausse. Si vous breaksortez de la boucle, ou si une exception est levée, elle ne sera pas exécutée.

Une façon de penser est comme une construction if / else par rapport à la condition:

if condition:
    handle_true()
else:
    handle_false()

est analogue à la construction en boucle:

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

Un exemple pourrait être dans le sens de:

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
la source
42
"La clause else n'est exécutée que lorsque votre condition while devient fausse." Le libellé ici implique que votre état while passe d'un état vrai à faux et que le reste sera exécuté. Cependant, si le temps n'est jamais vrai, la clause else sera toujours exécutée.
user597608
pseudocode Alors corrigez-moi si je me trompe, mais c'est exactement la même chose while {} something sauf que le somethingsera ignoré si vous êtes breakdans la whileboucle.
Daniel Kaplan
2
Le pseudocode le plus précis serait peut-être: while (True) {if (cond) {handle_true (); } else {handle_false (); Pause; }}
VinGarcia
2
"ne passez pas, ne collectez pas 200", haha, tous ceux qui savent d'où cela vient ont eu une bonne enfance
Stefan Octavian
102

La elseclause est exécutée si vous quittez un bloc normalement, en atteignant la condition de boucle ou en tombant du bas d'un bloc try. Il n'est pas exécuté si vous breakou returnhors d'un bloc, ou déclenchez une exception. Cela fonctionne non seulement pendant et pour les boucles, mais aussi pour les blocs.

Vous le trouvez généralement dans des endroits où normalement vous quitteriez une boucle tôt, et courir à la fin de la boucle est une occasion inattendue / inhabituelle. Par exemple, si vous parcourez une liste à la recherche d'une valeur:

for value in values:
    if value == 5:
        print "Found it!"
        break
else:
    print "Nowhere to be found. :-("
John Kugelman
la source
1
En fait, une construction assez utile pour une telle chose. Je ne sais pas combien de fois j'ai mis found_it=Falseau début d'une boucle, puis je fais un test si found_ità la fin
Cruncher
42

En réponse à Is there a specific reason?, voici une application intéressante: sortir de plusieurs niveaux de bouclage.

Voici comment cela fonctionne: la boucle externe a une coupure à la fin, donc elle ne serait exécutée qu'une seule fois. Cependant, si la boucle interne se termine (ne trouve aucun diviseur), alors elle atteint l'instruction else et la rupture externe n'est jamais atteinte. De cette façon, une coupure dans la boucle intérieure sortira des deux boucles, plutôt qu'une seule.

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!'

Pour les deux whileet les forboucles, l' elseinstruction est exécutée à la fin, sauf si elle a breakété utilisée.

Dans la plupart des cas, il existe de meilleures façons de le faire (en l'enveloppant dans une fonction ou en levant une exception), mais cela fonctionne!

marque
la source
1
Je n'ai pas déçu, mais je pense que je sais pourquoi quelqu'un l'a fait. Vous ne répondez pas à la question et vous fournissez 14 lignes de code avec seulement 2 lignes de description. S'il y a un rapport avec la question posée, vous ne nous le dites pas ...
BlueEel
1
@BlueEel merci pour la rétroaction! J'ai ajouté plus d'explications sur le code et expliqué plus clairement comment cela répond à la question (car il répond en partie).
Mark
Vous avez réussi à mettre votre code en contexte et bien que vous ne répondiez pas à toutes les questions, je vois maintenant la pertinence. J'ai voté pour votre réponse car elle est maintenant utile aux nouveaux arrivants et aux novices (comme moi en ce qui concerne le python). - Merci, j'ai appris quelque chose.
BlueEel
J'aime l'application simple - maintenant je vois pourquoi quelqu'un pourrait l'utiliser. Bien que je n'en ai jamais vu le besoin.
gabe
L'exemple montre l'utilisation de for / else mais la question portait spécifiquement sur while / else.
Ian Goldby
20

La clause else est exécutée lorsque la condition while est évaluée à false.

De la documentation :

L'instruction while est utilisée pour une exécution répétée tant qu'une expression est vraie:

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

Cela teste à plusieurs reprises l'expression et, si elle est vraie, exécute la première suite; si l'expression est fausse (ce qui peut être la première fois qu'elle est testée), la suite de la elseclause, si elle est présente, est exécutée et la boucle se termine.

Une breakinstruction exécutée dans la première suite termine la boucle sans exécuter la elsesuite de la clause. Une continueinstruction exécutée dans la première suite ignore le reste de la suite et revient à tester l'expression.

Mark Rushakoff
la source
15

Ma réponse se concentrera sur QUAND nous pouvons utiliser while / for-else.

À première vue, il ne semble pas y avoir de différence lors de l'utilisation

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

et

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

Parce que l' print 'ELSE'instruction semble toujours exécutée dans les deux cas (à la fois lorsque la whileboucle est terminée ou non).

Ensuite, ce n'est différent que lorsque l'instruction print 'ELSE'ne sera pas exécutée. C'est quand il y a un breakbloc de code souswhile

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

Si différent de:

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 ne fait pas partie de cette catégorie, car elle fait le même effet dans deux cas ci-dessus.

La levée d'exception ne provoque pas non plus de différence, car lorsqu'elle se déclenche, où le code suivant sera exécuté est dans le gestionnaire d'exceptions (sauf le bloc), le code dans la elseclause ou juste après la whileclause ne sera pas exécuté.

HVNSweeting
la source
4

Je sais que c'est une vieille question mais ...

Comme l'a dit Raymond Hettinger, il devrait être appelé à la while/no_breakplace de while/else.
Je trouve cela facile à comprendre et si vous regardez cet extrait.

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

Maintenant, au lieu de vérifier la condition après la boucle while, nous pouvons l'échanger elseet nous débarrasser de ce contrôle.

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

Je le lis toujours while/no_breakpour comprendre le code et cette syntaxe a beaucoup plus de sens pour moi.

Iluvatar
la source
3

La clause else n'est exécutée que lorsque la condition while devient fausse.

Voici quelques exemples:

Exemple 1: Initialement, la condition est fausse, donc la clause else est exécutée.

i = 99999999

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

PRODUCTION:

this

Exemple 2: La condition while i < 5 n'est jamais devenue fausse car elle i == 3rompt la boucle, donc la clause else n'a pas été exécutée.

i = 0

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

PRODUCTION:

0
1
2
3

Exemple 3: La condition while i < 5 est devenue fausse quand iwas 5, donc la clause else a été exécutée.

i = 0

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

PRODUCTION:

0
1
2
3
4
this
Saif Ur Rahman
la source
0

L' else:instruction est exécutée lorsque et seulement lorsque la boucle while ne remplit plus sa condition (dans votre exemple, quand n != 0est false).

Donc, la sortie serait la suivante:

5
4
3
2
1
what the...
BoltClock
la source
Je sais, mais ce genre de temps / autre ne fonctionne pas en Java. Je trouve cela très intéressant quand j'ai compris que cela fonctionne en Python. J'étais juste curieux et je voulais connaître la raison technique.
Ivan
6
@Ivan: Ce n'est pas tant que cela ne fonctionne pas le travail en Java , mais qu'il n'existe en Java. Il pourrait être fait fonctionner, si quelqu'un voulait l'ajouter à la langue.
Ignacio Vazquez-Abrams
1
Non, tandis que False: .. else .. exécute toujours la clause else. Il est plus précis de dire: sinon, il n'est pas exécuté si la boucle est rompue.
Leo Ufimtsev
0

Sinon est exécuté si la boucle while ne s'est pas cassée.

J'aime un peu y penser avec une métaphore «coureur».

Le "sinon", c'est comme franchir la ligne d'arrivée, peu importe si vous avez commencé au début ou à la fin de la piste. "else" n'est pas exécuté uniquement si vous cassez quelque part entre les deux.

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.

Les cas d'utilisation principaux utilisent cette rupture des boucles imbriquées ou si vous souhaitez exécuter certaines instructions uniquement si la boucle ne s'est pas interrompue quelque part (pensez que la rupture est une situation inhabituelle).

Par exemple, ce qui suit est un mécanisme sur la façon de sortir d'une boucle interne sans utiliser de variables ou essayer / attraper:

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
la source
-1

La meilleure utilisation de la construction 'while: else:' en Python devrait être si aucune boucle n'est exécutée dans 'while' alors l'instruction 'else' est exécutée. La façon dont cela fonctionne aujourd'hui n'a pas de sens car vous pouvez utiliser le code ci-dessous avec les mêmes résultats ...

n = 5
while n != 0:
    print n
    n -= 1
print "what the..."
Jean Ferri
la source
8
Non, la différence est que le elsebloc ne sera pas exécuté si vous quittez la boucle à l'aide de breakou du returnmot - clé. Dans votre exemple, printsera également exécuté si la boucle s'est terminée sur breakcommande.
notsurewhattodo
2
Vous décrivez comment la plupart des gens souhaitent que la fonctionnalité fonctionne, pas comment elle fonctionne réellement!
dotancohen
-2

Il est utile pour l'interaction sociale.

while (Date != "January 1st"):
    time.sleep(1)
else:
    print("Happy new year!")
Guimoute
la source
2
Et quel est exactement le but de l' elseici? Le code fait exactement la même chose sans lui.
wovano
Si votre horloge et votre calendrier breakpendant votre compte à rebours, ne pas utiliser elsevous fera dire "Bonne année!" instantanément, ce qui n'a aucun sens.
Guimoute
@Guimote, que voulez-vous dire par "si votre horloge et votre calendrier break"? Il n'y breaken a pas dans le code.
wovano