Pourquoi python utilisation 'd'autre' après les boucles for et while?
je comprends comment cette construction fonctionne:
for i in range(10):
print(i)
if i == 9:
print("Too big - I'm giving up!")
break;
else:
print("Completed successfully")
mais je ne comprends pas pourquoi else
est utilisé comme mot clé ici, car il suggère que le code en question ne fonctionne que si le bloc for
n'est pas complet, ce qui est le contraire de ce qu'il fait! Peu importe ce que j'en pense, mon cerveau ne peut pas progresser de façon transparente de la déclaration for
au bloc else
. Pour moi, continue
ou continuewith
aurait plus de sens (et je suis en essayant de m'entraîner à le lire comme tel).
je me demande comment les codeurs Python lisent cette construction dans leur tête (ou à voix haute, si vous voulez). Peut-être que je manque quelque chose qui rendrait ces blocs de code plus facilement déchiffrables?
17 réponses
c'est une construction étrange même pour les codeurs Python assaisonnés. Lorsqu'il est utilisé conjointement avec des boucles signifie "trouver un élément de l'itératif, d'autre si aucune n'a été trouvé ...". Comme dans:
found_obj = None
for obj in objects:
if obj.key == search_key:
found_obj = obj
break
else:
print('No object found.')
Mais quand vous voyez cette construction, une meilleure alternative est d'encapsuler la recherche dans une fonction:
def find_obj(search_key):
for obj in objects:
if obj.key == search_key:
return obj
ou utilisez une liste de compréhension:
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.')
Il n'est pas sémantiquement équivalent pour les deux autres versions, mais fonctionne assez bien dans le code critique Non-performance où il n'a pas d'importance que vous itériez la liste entière ou non. D'autres peuvent être en désaccord, mais personnellement j'éviterais d'utiliser les blocs for-else ou while-else dans le code de production.
Voir aussi [Python-idées] Résumé de pour...autres fils
une construction commune est d'exécuter une boucle jusqu'à ce que quelque chose soit trouvé et puis de sortir de la boucle. Le problème est que si je sors de la boucle ou si la boucle se termine, je dois déterminer quel cas s'est produit. Une méthode consiste à créer un drapeau ou une variable de stockage qui me permettra de faire un deuxième test pour voir comment la boucle a été quitté.
par exemple, supposons que je dois chercher dans une liste et traiter chaque élément jusqu'à ce qu'un élément de drapeau soit trouvé et puis arrêter le traitement. Si l' l'élément de drapeau est manquant puis une exception doit être soulevée.
utilisant le Python for
... else
construisez vous avez
for i in mylist:
if i == theflag:
break
process(i)
else:
raise ValueError("List argument missing terminal flag.")
Comparez cela à une méthode qui n'utilise pas ce sucre syntaxique:
flagfound = False
for i in mylist:
if i == theflag:
flagfound = True
break
process(i)
if not flagfound:
raise ValueError("List argument missing terminal flag.")
dans le premier cas, le raise
est étroitement lié à la boucle for avec laquelle il travaille. Dans la seconde, la liaison n'est pas aussi forte et des erreurs peuvent être introduites lors de l'entretien.
il y a une excellente présentation de Raymond Hettinger, intitulée Transforming Code into Beautiful, Idiomatic Python , dans laquelle il aborde brièvement l'histoire de la construction for ... else
. La section pertinente est "distinction multiple exit points in loops " commençant à 15:50 et continuant pendant environ trois minutes. Voici les hauts points:
- le
for ... else
construction a été conçu par Donald Knuth en remplacement de certainsGOTO
cas d'utilisation; - réutiliser le mot-clé
else
avait du sens parce que "C'est ce que Knuth utilisé, et les gens savaient, à ce moment-là, tous [for
déclarations] avait intégré unif
etGOTO
en dessous, et ils s'attendaient à laelse
; " - en rétrospective, il aurait dû être appelé "no break" (ou peut-être "nobreak"), et alors il ne serait pas déroutant.*
donc, si la question est, " pourquoi ne changent-ils pas ce mot clé?"puis Chat Plus Plus probablement donné la réponse la plus précise – à ce point, il serait trop destructeur pour code existant pour être pratique. Mais si la question que vous posez vraiment est pourquoi else
a été réutilisé en premier lieu, Eh bien, apparemment cela semblait être une bonne idée à l'époque.
Personnellement, j'aime le compromis de commentant # no break
en ligne partout où le else
pourrait être confondu, à un coup d'oeil, comme appartenant à l'intérieur de la boucle. C'est assez clair et concis. Cette option obtient une brève mention dans le résumé que Bjorn lié à la fin de sa réponse:
pour être complet, je dois mentionner qu'avec un léger changement dans syntaxe, les programmeurs qui veulent cette syntaxe peuvent l'avoir dès maintenant:
for item in sequence: process(item) else: # no break suite
* citation Bonus de cette partie de la vidéo: "tout comme si nous avons appelé lambda makefunction, personne ne demanderait, " que fait lambda?"
parce qu'ils ne voulaient pas introduire un nouveau mot-clé à la langue. Chacun vole un identifiant et cause des problèmes de compatibilité à l'envers, donc c'est généralement le dernier recours.
le moyen le plus facile que j'ai trouvé pour "obtenir" ce que le for/else a fait, et plus important encore, quand l'utiliser, était de se concentrer sur l'endroit où la déclaration de pause saute à. La construction For / else est un bloc unique. Le break sort du bloc, et saute donc sur la clause "else". Si le contenu de la clause else suivait simplement la clause for, elle ne serait jamais dépassée, et donc la logique équivalente devrait être fournie en la mettant dans un si. Cela a déjà été dit, mais pas tout à fait dans ces mots, de sorte qu'il peut aider quelqu'un d'autre. Essayez d'exécuter le fragment de code suivant. Je suis tout à fait en faveur du commentaire "Pas de pause" pour plus de clarté.
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')
Je l'ai lu quelque chose comme:
Si encore sur les conditions d'exécution de la boucle, faire des choses, else faire quelque chose d'autre.
je pense que la documentation a une grande explication de else , continue
[...] il est exécuté lorsque la boucle se termine par épuisement de la liste (avec for) ou lorsque la condition devient false (avec while), mais pas lorsque la boucle est terminée par une instruction break."
pour faire simple, vous pouvez penser à lui comme cela;
- si elle rencontre la commande
break
dans la bouclefor
, la partieelse
ne sera pas appelée. - si elle ne rencontre pas la commande
break
dans la bouclefor
, la partieelse
sera appelée.
en d'autres termes, si pour l'itération de boucle n'est pas "cassé" avec break
, le else
la partie sera appelée.
c'est si simple.
puisque la partie technique a été pratiquement répondu, mon commentaire est juste en relation avec le confusion qui produisent ce recyclé mot-clé.
étant Python un très éloquent langage de programmation, l'usage abusif d'un mot-clé est plus notoire. Le mot-clé else
décrit parfaitement une partie du flux d'un arbre de décision,"si vous ne pouvez pas faire ceci, (sinon) faites cela". C'est implicite dans notre propre langue.
à la place, l'utilisation de ce mot-clé avec les énoncés while
et for
crée de la confusion. La raison, notre carrière en tant que programmeurs nous a appris que la déclaration else
réside dans un arbre de décision; son portée logique , un wrapper que conditionnellement retourner un chemin à suivre. En attendant, les déclarations de boucle ont un but figuratif explicite à atteindre quelque. Le but est atteint après une itération d'un processus.
if / else
indiquer un chemin pour suivre . Boucles suivre un chemin jusqu'à ce que le" but "soit terminé .
Le problème est que else
est un mot qui définissent clairement la dernière option dans une condition. Les sémantiques du mot sont à la fois partagés par Python et le langage humain. Mais l'autre mot dans le langage humain n'est jamais utilisé pour indiquer les actions que quelqu'un ou quelque chose va prendre après que quelque chose est terminé. Il sera utilisé si, dans le processus de la terminer, une question s'élève (plus comme un pause déclaration).
À la fin, le mot-clé restera en Python. Il est clair que c'était une erreur, plus clair quand chaque programmeur essaye de trouver une histoire pour comprendre son utilisation comme un dispositif mnémotechnique. J'aurais aimé, si ils ont choisi à la place le mot-clé then
. Je crois que ce mot-clé s'inscrit parfaitement dans ce flux itératif, le payoff après la boucle.
il ressemble à cette situation qu'un enfant a après avoir suivi chaque étape dans l'assemblage d'un jouet: et puis quel Papa?
Je l'ai lu comme "quand le iterable
est épuisé complètement, et l'exécution est sur le point de procéder à la déclaration suivante après avoir terminé le for
, la clause else sera exécutée."Ainsi, lorsque l'itération est brisée par break
, cela ne sera pas exécuté.
je suis d'accord, c'est plus comme un " elif [condition(s) la collecte de pause]'.
je sais que c'est un vieux fil, mais je regarde dans la même question en ce moment, et je ne suis pas sûr que quelqu'un a capturé la réponse à cette question dans la façon dont je la comprends.
pour moi, il y a trois façons de "lire" les énoncés else
dans For... else
ou While... else
, qui sont tous équivalents, sont:
-
else
==
if the loop completes normally (without a break or error)
-
else
==
if the loop does not encounter a break
-
else
==
else not (condition raising break)
(probablement il y a une telle condition, ou vous n'auriez pas une boucle)
donc, essentiellement, le "else" dans une boucle est vraiment un " elif ..." où.' .."est (1) Pas de pause, ce qui est équivalent à(2) pas [condition (s) pause levée].
je pense que la clé est que le else
est inutile sans le "break", donc un for...else
comprend:
for:
do stuff
conditional break # implied by else
else not break:
do more stuff
ainsi, les éléments essentiels d'une boucle for...else
sont les suivants, et vous les liriez dans un anglais plus simple comme:
for:
do stuff
condition:
break
else: # read as "else not break" or "else not condition"
do more stuff
comme les autres affiches ont dit, une pause est généralement soulevée quand vous êtes en mesure de localiser ce que votre boucle cherche, de sorte que le else:
devient "que faire si l'élément cible n'est pas situé".
exemple
vous pouvez également utiliser la manipulation d'exception, les pauses, et pour les boucles tous ensemble.
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")
résultat
x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run
exemple
exemple Simple avec une coupure frappée.
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")
Résultat
y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run
exemple
exemple Simple où il n'y a pas de rupture, aucune condition soulevant une rupture, et aucune erreur ne sont rencontrées.
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")
résultat
z: 0
z: 1
z: 2
z_loop complete without break or error
----------
le mot-clé else
peut prêter à confusion ici, et comme beaucoup de gens l'ont souligné, quelque chose comme nobreak
, notbreak
est plus approprié.
afin de comprendre for ... else ...
logiquement, comparez-le avec try...except...else
, pas if...else...
, la plupart des programmeurs python sont familiers avec le code suivant:
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.
de même, pensez à break
comme une sorte spéciale de 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
la différence est python
implique except break
et vous ne pouvez pas l'écrire, il devient donc:
for x in iterable:
do_something(x)
else:
print('no break encountered') # No break statement was encountered
Oui, je sais que cette comparaison peut être difficile et fatigante, mais elle clarifie la confusion.
dans le bloc de déclaration else
seront exécutés lorsque la boucle for
n'a pas été rompue.
for x in xrange(1,5):
if x == 5:
print 'find 5'
break
else:
print 'can not find 5!'
#can not find 5!
De la docs: break " et " continue, et d'autre Clauses sur les Boucles
les déclarations de boucle peuvent avoir une clause else; elle est exécutée lorsque la boucle se termine par épuisement de la liste (avec for) ou lorsque la condition devient false (avec while), mais pas lorsque la boucle est terminé par un break statement. Ceci est illustré par la boucle suivante, qui recherche des nombres premiers:
>>> 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
(Oui, c'est le code correct. Regardez attentivement: la clause else appartient à la boucle for, pas à la déclaration if.)
lorsqu'elle est utilisée avec une boucle, la clause else a plus en commun avec la clause else d'une instruction try qu'avec celle de if statements: la clause else d'une instruction try s'exécute lorsqu'aucune exception ne se produit, et une la clause else de loop s'exécute lorsqu'aucune rupture ne se produit. Pour en savoir plus sur la déclaration try et les exceptions, consultez la rubrique Gestion des Exceptions.
la déclaration continue, également empruntée à C, continue avec la prochaine itération de la boucle:
>>> 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
vous pourriez penser à lui comme,
else
comme dans le reste des choses, ou les autres choses, qui n'ont pas été faites dans la boucle.
voici un autre cas d'utilisation idiomatique à part la recherche. Disons que vous vouliez attendre qu'une condition soit vraie, par exemple qu'un port soit ouvert sur un serveur distant, avec un certain temps mort. Alors vous pourriez utiliser une while...else
construire comme ainsi:
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()
supposons que nous ayons une fonction
def broken(x) : return False if x==5 else True
ce qui signifie que seulement 5 ne sont pas cassés. Maintenant dans le cas cassé n'est jamais évalué avec 5: -
for x in range(4):
if not broken(x) : break
else:
print("Everything broken... doom is upon us")
donnera la sortie: -
Everything broken... doom is upon us
où lorsque cassé est évalué avec 5: -
for x in range(6):
if not broken(x) : break
else:
print("Everything broken... doom is upon us")
il n'imprimera rien. Donc dire indirectement qu'il y a au moins quelque chose ce qui n'est pas cassé.
cependant, au cas où vous voulez tricher et sauter quelque chose que vous avez trouvé était cassé. Qui est, continuer la boucle, même si vous avez trouvé 5 cassés, else sera toujours imprimé. C'est-à-dire: -
for x in range(6):
if not broken(x) : continue
else:
print("Everything broken... doom is upon us")
imprime
Everything broken... doom is upon us
j'espère qu'il efface la confusion au lieu d'en créer une nouvelle :-)
for i in range(3):
print(i)
if i == 2:
print("Too big - I'm giving up!")
break;
else:
print("Completed successfully")
"else" ici est follement simple, juste moyen
1, " si for clause
est rempli "
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")
c'est agaçant d'écrire des énoncés aussi longs que" for clause is completed", donc ils introduisent"else".
else
voici un si dans sa nature.
2, cependant, que diriez-vous de 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
donc c'est complètement logique combinaison:
if "for clause is completed" or "not run at all":
do else stuff
ou le mettre de cette façon:
if "for clause is not partially run":
do else stuff
ou par ici:
if "for clause not encounter a break":
do else stuff