The Forgotten Optional `else` in Python Loops

This post discusses Python’s for...else and while...else syntax, one of the most rarely used and misunderstood syntactic features in Python.

Both for and while loops in Python also take an optional else suite (like the if statement and the try statement do), which executes if the loop iteration completes normally. In other words, the else suite will be executed if we don’t exit the loop in any way other than its natural way. So, no break statements, no return statement, or no exceptions being raised inside the loop. Consider a simple (and useless) example:

>>> for i in range(5):
...     print(i)
... else:
...     print('Iterated over everything :)')
...
0
1
2
3
4
Iterated over everything :)

In the code above, we iterate over range(5) and print each number. Since we let the loop complete normally, the else suite is also executed and Iterated over everything :) is printed. Conversely, if we stop the loop, say with a break statement, then the else suite will not be executed:

>>> for i in range(5):
...     if i == 2:
...         break
...     print(i)
... else:
...     print('Iterated over everything :)')
...
0
1

Note that the else suite will be executed even if the sequences being iterated over by the loop is empty; after all the loop is still completing normally:

>>> for i in []:
...     print(i)
... else:
...     print('Still iterated over everything (i.e. nothing)')
...
Still iterated over everything (i.e. nothing)

Also, let’s not forget, all the above apply to while...else as well:

>>> i = 0
>>> while i <= 5:
...     i += 1
...     print i
... else:
...     print 'Yep'
... 
1
2
3
4
5
Yep

 But, why!?

A common use case for the else clause in loops is to implement search loops; say you’re performing a search for an item that meets a particular condition, and need to perform additional processing or raise an error if no acceptable value is found:

for x in data:
    if meets_condition(x):
        break
else:
    # raise error or do additional processing 

Without the else clause you would need to set a flag and then check that later to see if any of the values met the condition:

condition_is_met = False
for x in data:
    if meets_condition(x):
        condition_is_met = True

if not condition_is_met:
    # raise error or do additional processing

This isn’t really a big deal and it’s how you have to do it in many other languages. But like many other features of Python, the else clause can result in a more elegant and Pythonic code. Arguably, in the example above, using the it makes the code more The Zen of Python-friendly:

There is not a case where you have no choice but to use the else clause in a loop; you can always use flags etc. but the else clause can often make the code more elegant and readable. One might think it’s Pythonic and it makes intentions clearer (Hi!), while others might think it’s confusing and redundant! Personally, I stick to using the else clause in loops unless there is another approach that is more readable (I guess, for me, it usually all boils down to how readable the code will be).


Discussion on hackernews and reddit.

Nat Dunn of Webucator has also kindly created a video version of this post as part of a new free self-paced “Python Solutions from the Web” course they are creating that will be available on their Python Training page:

 
1,589
Kudos
 
1,589
Kudos

Now read this

Importing `*` in Python

This post discusses Python’s from <module> import * and from <package> import *, how they behave and why it may be (is!) a bad idea to use them. Importing * from a module from <module> import * means “I want access to... Continue →