How can I make sense of the `else` clause of Python loops?
Solution 1
The while
statement with an else
clause
while condition:
suite
else:
exhausted
is exactly equivalent to
while True:
if not condition:
exhausted
break
suite
The for
statement with an else
clause
for item in iterable:
suite
else:
exhausted
is exactly equivalent to
iterator = iter(iterable)
try:
while True:
item = next(iterator)
suite
except StopIteration:
exhausted
It helps understand the effect of a break
or continue
statement in the suite statement.
Note. — For the while
and for
statements without an else
clause, replace the exhausted statement with a pass
statement in the equivalent code.
To memorise the meaning of the else
clause, you can interpret a loop statement as
if loop_breaks:
pass
else:
exhausted
Solution 2
An if
statement runs its else
clause if its condition evaluates to false.
Identically, a while
loop runs the else clause if its condition evaluates to false.
This rule matches the behavior you described:
- In normal execution, the while loop repeatedly runs until the condition evaluates to false, and therefore naturally exiting the loop runs the else clause.
- When you execute a
break
statement, you exit out of the loop without evaluating the condition, so the condition cannot evaluate to false and you never run the else clause. - When you execute a
continue
statement, you evaluate the condition again, and do exactly what you normally would at the beginning of a loop iteration. So, if the condition is true, you keep looping, but if it is false you run the else clause. - Other methods of exiting the loop, such as
return
, do not evaluate the condition and therefore do not run the else clause.
for
loops behave the same way. Just consider the condition as true if the iterator has more elements, or false otherwise.
Solution 3
Better to think of it this way: The else
block will always be executed if everything goes right in the preceding for
block such that it reaches exhaustion.
Right in this context will mean no exception
, no break
, no return
. Any statement that hijacks control from for
will cause the else
block to be bypassed.
A common use case is found when searching for an item in an iterable
, for which the search is either called off when the item is found or a "not found"
flag is raised/printed via the following else
block:
for items in basket:
if isinstance(item, Egg):
break
else:
print("No eggs in basket")
A continue
does not hijack control from for
, so control will proceed to the else
after the for
is exhausted.
Solution 4
When does an if
execute an else
? When its condition is false. It is exactly the same for the while
/else
. So you can think of while
/else
as just an if
that keeps running its true condition until it evaluates false. A break
doesn't change that. It just jumps out of the containing loop with no evaluation. The else
is only executed if evaluating the if
/while
condition is false.
The for
is similar, except its false condition is exhausting its iterator.
continue
and break
don't execute else
. That isn't their function. The break
exits the containing loop. The continue
goes back to the top of the containing loop, where the loop condition is evaluated. It is the act of evaluating if
/while
to false (or for
has no more items) that executes else
and no other way.
Solution 5
This is what it essentially means:
for/while ...:
if ...:
break
if there was a break:
pass
else:
...
It's a nicer way of writing of this common pattern:
found = False
for/while ...:
if ...:
found = True
break
if not found:
...
The else
clause will not be executed if there is a return
because return
leaves the function, as it is meant to. The only exception to that which you may be thinking of is finally
, whose purpose is to be sure that it is always executed.
continue
has nothing special to do with this matter. It causes the current iteration of the loop to end which may happen to end the entire loop, and clearly in that case the loop wasn't ended by a break
.
try/else
is similar:
try:
...
except:
...
if there was an exception:
pass
else:
...
Related videos on Youtube
alexis
Updated on June 06, 2022Comments
-
alexis over 1 year
Many Python programmers are probably unaware that the syntax of
while
loops andfor
loops includes an optionalelse:
clause:for val in iterable: do_something(val) else: clean_up()
The body of the
else
clause is a good place for certain kinds of clean-up actions, and is executed on normal termination of the loop: I.e., exiting the loop withreturn
orbreak
skips theelse
clause; exiting after acontinue
executes it. I know this only because I just looked it up (yet again), because I can never remember when theelse
clause is executed.Always? On "failure" of the loop, as the name suggests? On regular termination? Even if the loop is exited with
return
? I can never be entirely sure without looking it up.I blame my persisting uncertainty on the choice of keyword: I find
else
incredibly unmnemonic for this semantics. My question is not "why is this keyword used for this purpose" (which I would probably vote to close, though only after reading the answers and comments), but how can I think about theelse
keyword so that its semantics make sense, and I can therefore remember it?I'm sure there was a fair amount of discussion about this, and I can imagine that the choice was made for consistency with the
try
statement'selse:
clause (which I also have to look up), and with the goal of not adding to the list of Python's reserved words. Perhaps the reasons for choosingelse
will clarify its function and make it more memorable, but I'm after connecting name to function, not after historical explanation per se.The answers to this question, which my question was briefly closed as a duplicate of, contain a lot of interesting back story. My question has a different focus (how to connect the specific semantics of
else
with the keyword choice), but I feel there should be a link to this question somewhere.-
Nick stands with Ukraine almost 3 years@alexis The edit by Dharman was made in an attempt to make your question not opinion based while maintaining the question itself, IMO the edit makes the post an awful lot better (and not worthy of closure)
-
alexis almost 3 years@Dharman, I appreciate your efforts but your edits completely distort the intent and content of the question. Please stop.
-
Nick stands with Ukraine almost 3 years"how can I think about the
else
keyword so that its semantics make sense, and I can therefore remember it?" - Explaining to you specifically how we can help you personally remember howelse
works isn't a helpful question, Dharman is the only reason I retracted a close vote on the question, because without it the question is opinion based -
alexis almost 3 yearsThank you for the explanation, @nick. Nevertheless, Dharman's title makes it a duplicate of a very different question. If you are convinced that this is too opinion-based, i can leave with your vote. But please leave the question alone.
-
alexis almost 3 yearsAlso the question is about making sense of this design, not about what it does.
-
-
alexis over 7 yearsWhat you say sounds very sensible, but lumping the three termination conditions together, "until [the condition] is False or breaks/continues", is wrong: Crucially, the
else
clause is executed if the loop is exited withcontinue
(or normally), but not if we exit withbreak
. These subtleties are why I'm trying to really grok whatelse
catches and what it does not. -
alexis over 7 yearsSounds very nice... but then you'd expect an
else
clause to be executed when things don't go right, wouldn't you? I'm already getting confused again... -
Tadhg McDonald-Jensen over 7 yearsI have to disagree with you on "Technically, It isn't [semantically similar to every other
else
]", since theelse
is run when none of the conditions in the for loop evaluate to True, as I demonstrate in my answer -
Moses Koledoye over 7 years@TadhgMcDonald-Jensen You can also break the loop on a
False
. So the question of how thefor
is broken depends on the use case. -
alexis over 7 yearsThat's right, I am asking for a way to somehow relate what happens to the English meaning of "else" (which is indeed reflected in other uses of
else
in python). You provide a good intuitive summary of whatelse
does, @Moses, but not of how we could associate this behavior with "else". If a different keyword was used (e.g.,nobreak
as mentioned in this answer to a related question), it would be easier to make sense of. -
alexis over 7 yearsRight. But a loop runs multiple times, so it's a little unclear how you mean to apply this to a for-loop. Can you clarify?
-
Moses Koledoye over 7 years@alexis From the link you added, given the etymology of this
else
, I think we'll have to accept the status quo :) -
alexis over 7 yearsWhat status quo do you mean? I certainly wasn't aiming for a change in Python's syntax!
-
Moses Koledoye over 7 yearsThat this
else
does not behave the way it sounds. And to understand it, you'll have to apply some abstraction like thenobreak
everyone already proposed. -
Mark Tolonen over 7 years@alexis yes I needed to clarify there. Edited. continue doesn't execute the else, but does return to the top of the loop which may then evaluate to false.
-
Mark Tolonen over 7 yearsIt really has nothing to do with "things going right". The else is purely executed when the
if
/while
condition evaluates to false orfor
is out of items.break
exists the containing loop (after theelse
).continue
goes back and evaluates the loop condition again. -
Tadhg McDonald-Jensen over 7 years@MosesKoledoye ok so in a chain of
if/elif
s the only way tobreak
out of the chain is for one of the conditionals to beTrue
, where as a for loop is exited with the explicitbreak
(and both are broken byreturn
or exception) I certainly don't think of things going "wrong" when the for loop needs to break. -
Moses Koledoye over 7 yearsGoing right is an oversimplification, and I already described what I meant by that in the answer.
-
alexis over 7 yearsWhere is the
else
? If you meant thedone:
label to stand proxy orelse:
, I believe you have it exactly backwards. -
zwol over 7 years@alexis The 'else' code would fill in the '...' immediately before the
done:
label. The overall correspondence is, maybe, best said thus: Python has theelse
-on-loop construct so that you can express this control flow pattern withoutgoto
. -
supercat over 7 yearsI 'd suggest that it could be enhanced by saying that the usual purpose of a for/else loop is to examine items until you've found what you're looking for and want to stop, or you run out of items. The "else" exists to handle the "you run out of items (without having found what you were looking for)" part.
-
Fabian Fagerholm over 7 years@supercat: Could be, but I don't know what the most common uses are out there. The
else
could also be used to do something when you're simply finished with all the items. Examples include writing a log entry, updating a user interface, or signaling some other process that you're done. Anything, really. Also, some pieces of code has the "successful" case end with abreak
inside the loop, and theelse
is used to handle the "error" case where you didn't find any suitable item during the iteration (maybe that was what you were thinking of?). -
supercat over 7 yearsThe case I was thinking of was precisely the case where the successful case ends with a "break", and the "else" handles a lack of success. If there's no "break" within a loop, the "else" code may as well simply follow the loop as part of the enclosing block.
-
alexis over 7 yearsThere are other ways to execute this control flow pattern, e.g. by setting a flag. That's what the
else
avoids. -
Fabian Fagerholm over 7 yearsUnless you need to distinguish between the case where the loop went through all the iterable items without interruption (and that was a successful case) and the case where it didn't. Then you have to put the "finalising" code in the loop's
else
block, or keep track of the result using other means. I basically agree, I'm just saying I don't know how people use this feature and therefore I'd like to avoid making assumptions of whether the "else
handles successful case" scenario or the "else
handles unsuccessful case" scenario is more common. But you have a good point, so comment upvoted! -
Bergi over 7 yearsI pretty much like this answer, but you can simplify: Omit the
end
label and just put thegoto loop
inside theif
body. Maybe even outdent by putting theif
on the same line as the label, and it suddenly looks very much like the orignal. -
Keiwan over 7 years@Bergi Yes, I think that makes it a bit clearer, thanks.
-
Nomenator over 7 yearsThis is a most excellent answer. Treat your loops like a series of elif statements and the else behaviour will expose its natural logic.
-
alexis over 7 yearsI like that, I think you're on to something. It ties in a little with how looping used to be implemented in the bad old days before loop keywords. (Namely: the check was placed at the bottom of the loop, with a
goto
the top on success.) But it's a shorter version of the top-voted answer... -
Winston Ewert over 7 years@alexis, subjective, but I find my way of expressing it easier to think about.
-
alexis over 7 yearsactually I agree. If only because it's pithier.
-
alexis over 7 yearsI also like this answer, but it is not drawing an analogy with a series of
elif
statements. There's an answer that does, and it has one net upvote. -
Tadhg McDonald-Jensen over 7 years@alexis I have redone my answer, I think it is a lot clearer now.
-
Tadhg McDonald-Jensen over 7 yearswell not exactly, a while loop could have the condition meet False right before it
break
s, in which case theelse
would not run but the condition is False. Similarly withfor
loops it canbreak
on the last element.