De nombreux programmeurs Python ignorent probablement que la syntaxe des while
boucles et des for
boucles comprend une else:
clause facultative :
for val in iterable:
do_something(val)
else:
clean_up()
Le corps de la else
clause est un bon endroit pour certains types d'actions de nettoyage et est exécuté à la fin normale de la boucle: c'est-à-dire, quitter la boucle avec return
ou break
sauter la else
clause; quitter après une continue
exécution. Je le sais uniquement parce que je viens de le chercher (encore une fois), parce que je ne me souviens jamais quand la else
clause est exécutée.
Toujours? Sur «échec» de la boucle, comme son nom l'indique? En cas de résiliation régulière? Même si la boucle est sortie avec return
? Je ne peux jamais être entièrement sûr sans le chercher.
Je blâme mon incertitude persistante sur le choix du mot-clé: je trouve else
incroyablement démnémonique pour cette sémantique. Ma question n'est pas "pourquoi ce mot-clé est-il utilisé à cette fin?" (Que je voterais probablement pour fermer, mais seulement après avoir lu les réponses et les commentaires), mais comment puis-je penser au else
mot - clé pour que sa sémantique ait un sens, et je peut donc s'en souvenir?
Je suis sûr qu'il y a eu beaucoup de discussions à ce sujet, et je peux imaginer que le choix a été fait par souci de cohérence avec la clause de la try
déclaration else:
(que je dois également consulter), et dans le but de ne pas ajouter à la liste des Les mots réservés de Python. Peut-être que les raisons du choix else
clarifieront sa fonction et la rendront plus mémorable, mais je suis après avoir connecté le nom à la fonction, pas après une explication historique en soi.
Les réponses à cette question , dont ma question a été brièvement clôturée comme un double, contiennent beaucoup d'histoire intéressante. Ma question a un objectif différent (comment relier la sémantique spécifique de else
avec le choix du mot clé), mais je pense qu'il devrait y avoir un lien vers cette question quelque part.
la source
else
signifie essentiellement "si la condition de continuation échoue". Dans une boucle for traditionnelle, la condition de continuation est généralementi < 42
, dans ce cas, vous pouvez voir cette partie commeif i < 42; execute the loop body; else; do that other thing
break
. Le cas d'utilisation canonique est celui où la boucle recherche quelque chose et se rompt lorsqu'elle le trouve. Leelse
n'est exécuté que si rien n'est trouvé.Réponses:
(Ceci est inspiré de la réponse de @Mark Tolonen.)
Une
if
instruction exécute saelse
clause si sa condition est évaluée à false. De la même manière, unewhile
boucle exécute la clause else si sa condition est évaluée à false.Cette règle correspond au comportement que vous avez décrit:
break
instruction, vous sortez de la boucle sans évaluer la condition, la condition ne peut donc pas être évaluée à false et vous n'exécutez jamais la clause else.continue
instruction, vous évaluez à nouveau la condition et faites exactement ce que vous feriez normalement au début d'une itération de boucle. Donc, si la condition est vraie, vous continuez à boucler, mais si elle est fausse, vous exécutez la clause else.return
, n'évaluent pas la condition et n'exécutent donc pas la clause else.for
les boucles se comportent de la même manière. Considérez simplement la condition comme vraie si l'itérateur a plus d'éléments, ou comme fausse dans le cas contraire.la source
elif
énoncés. Il y a une réponse qui fait, et il y a un vote positif net.break
s, auquel cas leelse
ne s'exécuterait pas mais la condition est False. De même avec desfor
boucles, il peutbreak
sur le dernier élément.Mieux vaut le penser de cette façon: le
else
bloc sera toujours exécuté si tout va bien dans lefor
bloc précédent de sorte qu'il atteigne l'épuisement.Droit dans ce contexte signifie pas
exception
, nonbreak
, nonreturn
. Toute instruction qui détourne le contrôlefor
provoquera leelse
contournement du bloc.Un cas d'utilisation courant est trouvé lors de la recherche d'un élément dans un
iterable
, pour lequel la recherche est soit annulée lorsque l'élément est trouvé, soit un"not found"
drapeau est levé / imprimé via leelse
bloc suivant :A
continue
ne détourne pas le contrôle defor
, donc le contrôle passera auelse
après que lefor
est épuisé.la source
else
clause soit exécutée lorsque les choses ne vont pas bien, n'est-ce pas? Je suis déjà de nouveau confus ...else
]", puisque leelse
est exécuté lorsqu'aucune des conditions de la boucle for n'est évaluée à True, comme je le démontre dans ma réponseFalse
. Donc, la question de savoir comment lefor
est cassé dépend du cas d'utilisation.else
en python). Vous fournissez un bon résumé intuitif de ce queelse
fait, @Moses, mais pas de la façon dont nous pourrions associer ce comportement à «autre». Si un mot-clé différent était utilisé (par exemple,nobreak
comme mentionné dans cette réponse à une question connexe), il serait plus facile à comprendre.if
/ estwhile
évaluée à false oufor
est à court d'éléments.break
existe la boucle contenant (après leelse
).continue
revient en arrière et évalue à nouveau la condition de la boucle.Quand un
if
exécute-else
t-il un ? Lorsque sa condition est fausse. C'est exactement la même chose pour lewhile
/else
. Vous pouvez donc considérerwhile
/else
comme un simpleif
qui continue d'exécuter sa condition vraie jusqu'à ce qu'il évalue false. Abreak
ne change pas cela. Il saute juste hors de la boucle contenant sans évaluation. Leelse
n'est exécuté que si l' évaluation de la conditionif
/while
est fausse.Le
for
est similaire, sauf que sa condition fausse épuise son itérateur.continue
etbreak
ne pas exécuterelse
. Ce n'est pas leur fonction. Lebreak
sort de la boucle contenant. Lecontinue
retourne en haut de la boucle contenant, où la condition de la boucle est évaluée. C'est l'acte d'évaluerif
/while
à faux (oufor
qui n'a plus d'éléments) qui s'exécuteelse
et pas d'autre moyen.la source
else
clause est exécutée si la boucle est quittée aveccontinue
(ou normalement), mais pas si nous sortons avecbreak
. Ces subtilités sont la raison pour laquelle j'essaie de vraiment grok ce quielse
capture et ce qu'il ne fait pas.Voici ce que cela signifie essentiellement:
C'est une manière plus agréable d'écrire ce modèle commun:
La
else
clause ne sera pas exécutée s'il y a unreturn
carreturn
quitte la fonction comme prévu. La seule exception à ce à laquelle vous pensez peut-être estfinally
, dont le but est d'être sûr qu'il est toujours exécuté.continue
n'a rien de spécial à voir avec cette question. Cela provoque la fin de l'itération actuelle de la boucle, ce qui peut arriver à terminer la boucle entière, et clairement dans ce cas, la boucle n'a pas été terminée par unbreak
.try/else
est similaire:la source
Si vous pensez à vos boucles comme une structure similaire à celle-ci (un peu pseudo-code):
cela pourrait avoir un peu plus de sens. Une boucle est essentiellement juste une
if
instruction qui est répétée jusqu'à ce que la condition le soitfalse
. Et c'est le point important. La boucle vérifie sa condition et voit qu'elle estfalse
, donc exécute leelse
(comme une normaleif/else
) et ensuite la boucle est terminée.Notez donc que le
else
seul get est exécuté lorsque la condition est vérifiée . Cela signifie que si vous quittez le corps de la boucle en cours d'exécution avec par exemple areturn
ou abreak
, puisque la condition n'est pas vérifiée à nouveau, leelse
cas ne sera pas exécuté.A
continue
d'autre part arrête l'exécution en cours, puis revient pour vérifier à nouveau l'état de la boucle, c'est pourquoi leelse
peut être atteint dans ce scénario.la source
end
étiquette et mettez simplement l'goto loop
intérieur duif
corps. Peut-être même devancé en mettant leif
sur la même ligne que l'étiquette, et cela ressemble soudainement à l'original.Mon coup de tête avec la
else
clause de la boucle a été lorsque je regardais une conférence de Raymond Hettinger , qui a raconté une histoire sur la façon dont il pensait qu'elle aurait dû être appeléenobreak
. Jetez un œil au code suivant, que pensez-vous qu'il ferait?Que pensez-vous que cela fait? Eh bien, la partie qui dit
nobreak
ne serait exécutée que si unebreak
instruction n'était pas touchée dans la boucle.la source
Habituellement, j'ai tendance à penser à une structure de boucle comme celle-ci:
Pour ressembler beaucoup à un nombre variable d'
if/elif
instructions:Dans ce cas, l'
else
instruction sur la boucle for fonctionne exactement comme l'else
instruction sur la chaîne deelif
s, elle ne s'exécute que si aucune des conditions avant qu'elle n'évalue à True. (ou interrompre l'exécution avecreturn
ou une exception) Si ma boucle ne correspond pas à cette spécification, je choisis généralement de ne pas utiliserfor: else
pour la raison exacte pour laquelle vous avez posé cette question: ce n'est pas intuitif.la source
D'autres ont déjà expliqué la mécanique de
while/for...else
, et la référence du langage Python 3 a la définition faisant autorité (voir while et for ), mais voici mon mnémonique personnel, FWIW. Je suppose que la clé pour moi a été de diviser cela en deux parties: une pour comprendre la signification duelse
en relation avec la boucle conditionnelle, et une pour comprendre le contrôle de boucle.Je trouve qu'il est plus facile de commencer par comprendre
while...else
:Le
for...else
mnémonique est fondamentalement le même:Dans les deux cas, la
else
pièce n'est atteinte que lorsqu'il n'y a plus d'articles à traiter et que le dernier article a été traité de manière régulière (c'est-à-dire nonbreak
oureturn
). Acontinue
revient simplement et voit s'il y a d'autres éléments. Mon mnémonique pour ces règles s'applique à la foiswhile
etfor
:- avec "loop back to start" signifiant, évidemment, le début de la boucle où l'on vérifie s'il y a plus d'éléments dans l'itérable, donc en ce qui le
else
concerne,continue
ne joue vraiment aucun rôle.la source
else
peut également être utilisé pour faire quelque chose lorsque vous avez simplement terminé avec tous les éléments. Les exemples incluent l'écriture d'une entrée de journal, la mise à jour d'une interface utilisateur ou la signalisation d'un autre processus que vous avez terminé. Rien? Vraiment. En outre, certains morceaux de code ont la fin de cas "réussie" avec unbreak
à l'intérieur de la boucle, et leelse
est utilisé pour gérer le cas "erreur" où vous n'avez trouvé aucun élément approprié pendant l'itération (peut-être que c'était ce que vous pensiez de?).else
bloc de la boucle , ou suivre le résultat en utilisant d'autres moyens. Je suis fondamentalement d'accord, je dis simplement que je ne sais pas comment les gens utilisent cette fonctionnalité et par conséquent, j'aimerais éviter de faire des hypothèses sur le fait que leelse
scénario " gère les cas réussis" ou "else
gère les cas infructueux" est plus courant. Mais vous avez un bon point, alors commentez!Dans le développement piloté par les tests (TDD), lorsque vous utilisez le paradigme Transformation Priority Premise , vous traitez les boucles comme une généralisation d'instructions conditionnelles.
Cette approche se combine bien avec cette syntaxe, si vous ne considérez que des instructions simples
if/else
(nonelif
):se généralise à:
bien.
Dans d'autres langues, les étapes TDD d'un cas unique à des cas avec des collections nécessitent plus de refactorisation.
Voici un exemple du blog 8thlight :
Dans l'article lié au blog 8thlight, le kata Word Wrap est considéré: l'ajout de sauts de ligne aux chaînes (la
s
variable dans les extraits ci-dessous) pour les faire correspondre à une largeur donnée (lalength
variable dans les extraits ci-dessous). À un moment donné, l'implémentation se présente comme suit (Java):et le test suivant, qui échoue actuellement, est:
Nous avons donc du code qui fonctionne de manière conditionnelle: lorsqu'une condition particulière est remplie, un saut de ligne est ajouté. Nous voulons améliorer le code pour gérer plusieurs sauts de ligne. La solution présentée dans l'article propose d'appliquer la transformation (if-> while) , cependant l'auteur fait un commentaire que:
ce qui oblige à apporter plus de modifications au code dans le contexte d'un test échoué:
Dans TDD, nous voulons écrire le moins de code possible pour que les tests réussissent. Grâce à la syntaxe de Python, la transformation suivante est possible:
de:
à:
la source
La façon dont je le vois, se
else:
déclenche lorsque vous itérez au-delà de la fin de la boucle.Si vous
break
oureturn
ouraise
vous n'itérez pas au-delà de la fin de la boucle, vous vous arrêtez immédiatement et leelse:
bloc ne fonctionnera donc pas. Si vouscontinue
continuez à itérer au-delà de la fin de la boucle, puisque continuer passe simplement à l'itération suivante. Cela n'arrête pas la boucle.la source
goto
succès en haut.) Mais c'est une version plus courte de la réponse la plus votée ...Pensez à la
else
clause comme faisant partie de la construction de boucle;break
sort entièrement de la construction de la boucle et saute ainsi laelse
clause.Mais en réalité, mon mapping mental est simplement que c'est la version `` structurée '' du pattern C / C ++:
Ainsi, lorsque je le rencontre
for...else
ou que je l' écris moi-même, plutôt que de le comprendre directement , je le traduis mentalement dans la compréhension ci-dessus du modèle, puis je détermine quelles parties de la syntaxe python correspondent à quelles parties du modèle.(Je mets `` structuré '' entre guillemets effrayants car la différence n'est pas de savoir si le code est structuré ou non, mais simplement s'il existe des mots-clés et une grammaire dédiés à la structure particulière)
la source
else
? Si vous vouliez que l'done:
étiquette soit un proxy ouelse:
, je crois que vous l'avez exactement à l'envers.done:
étiquette. La correspondance globale est peut-être mieux dite ainsi: Python a laelse
construction -on-loop afin que vous puissiez exprimer ce modèle de flux de contrôle sansgoto
.else
évite.Si vous vous associez
else
avecfor
, cela pourrait être déroutant. Je ne pense pas que le mot-cléelse
était un excellent choix pour cette syntaxe, mais si vous associezelse
avecif
qui contientbreak
, vous pouvez voir que cela a du sens.else
est à peine utile s'il n'y a pas deif
déclaration précédente et je pense que c'est pourquoi le concepteur de syntaxe a choisi le mot-clé.Permettez-moi de le démontrer en langage humain.
la source
La façon dont j'y pense, la clé est de considérer la signification de
continue
plutôt que deelse
.Les autres mots-clés que vous mentionnez sortent de la boucle (sort anormalement) alors que ce
continue
n'est pas le cas, il saute simplement le reste du bloc de code à l'intérieur de la boucle. Le fait qu'elle puisse précéder la terminaison de la boucle est accessoire: la terminaison se fait en fait de façon normale par évaluation de l'expression conditionnelle de la boucle.Ensuite, vous devez simplement vous rappeler que la
else
clause est exécutée après la fin de la boucle normale.la source
la source