Python Language Loops with an "else" clause


Example

The for and while compound statements (loops) can optionally have an else clause (in practice, this usage is fairly rare).

The else clause only executes after a for loop terminates by iterating to completion, or after a while loop terminates by its conditional expression becoming false.

for i in range(3):
    print(i)
else:
    print('done')

i = 0
while i < 3:
    print(i)
    i += 1
else:
    print('done')

output:

 0
 1
 2
 done

The else clause does not execute if the loop terminates some other way (through a break statement or by raising an exception):

for i in range(2):
    print(i)
    if i == 1:
        break
else:
    print('done')

output:

0
1

Most other programming languages lack this optional else clause of loops. The use of the keyword else in particular is often considered confusing.

The original concept for such a clause dates back to Donald Knuth and the meaning of the else keyword becomes clear if we rewrite a loop in terms of if statements and goto statements from earlier days before structured programming or from a lower-level assembly language.

For example:

while loop_condition():
    ...
    if break_condition():
        break
    ...

is equivalent to:

# pseudocode

<<start>>:
if loop_condition():
    ...
    if break_condition():
        goto <<end>>
    ...
    goto <<start>>

<<end>>:

These remain equivalent if we attach an else clause to each of them.

For example:

while loop_condition():
    ...
    if break_condition():
        break
    ...
else:
    print('done')

is equivalent to:

# pseudocode

<<start>>:
if loop_condition():
    ...
    if break_condition():
        goto <<end>>
    ...
    goto <<start>>
else:
    print('done')

<<end>>:

A for loop with an else clause can be understood the same way. Conceptually, there is a loop condition that remains True as long as the iterable object or sequence still has some remaining elements.

Why would one use this strange construct?

The main use case for the for...else construct is a concise implementation of search as for instance:

a = [1, 2, 3, 4]
for i in a:
    if type(i) is not int:
        print(i)
        break
else:
    print("no exception") 

To make the else in this construct less confusing one can think of it as "if not break" or "if not found".

Some discussions on this can be found in [Python-ideas] Summary of for...else threads, Why does python use 'else' after for and while loops? , and Else Clauses on Loop Statements