One of the more uncommon aspects of the Python programming language is how it allows
else blocks in multiple types of compound statements. Python has the classic
if-else, but it also has a
for-else construct. And today I want to show you a simple use for it.
A Simple, Common Task
For the sake of example, let’s say that we have a list of forum users. We want to search through that list until we find a user which is an administrator. If we cannot find such a user we will raise a
So in general, we are searching for a needle in a haystack and raising an error if that needle doesn’t exist.
The Traditional Implementation
admin = None for user in all_users: if user.is_admin() == True: admin = user break if admin is None: raise UserNotFound
Taking Advantage of
First let’s consider the general structure:
for user in all_users: # Code that might 'break' else: # Code to run if the loop does not 'break'
In the for-loop we can use
break to exit the loop immediately after we find the user we’re searching for. When we
break inside of a loop Python will not execute the code in the
else block. But if the for-loop runs to completion, i.e. it never
break‘s, then Python runs the code in our
else block. This behavior allows us to rewrite the original example like so:
for user in all_users: if user.is_admin() == True: admin = user break else: raise UserNotFound
Personally I find this easier to read. In the original
if-else example we created a variable outside the for-loop and raised an error based on logic that’s structurally disconnected to the loop itself. But by using
for-else we not only save some lines of code, we also tie the error-raising code directly to the loop which may trigger that error, leading to more cohesive code.
A simple concept overall, but one which I often do not see since most similar languages do not have a
for-else construct. You can write
while-else constructs as well. So keep both in mind next time you’re writing a loop where you want to do something if the loop runs to completion and never
Update: 20 October 2015
I did not make it clear in the article that my intent was to focus on
for-else loops outside of functions where
return is unavailable. Reader Clément Pit-Claudel sent me an email about how he would write the loop if it were inside a function, and I agreed this structure would be better for a function:
def get_admin(all_users): for user in all_users: if user.is_admin(): # No need for == True here return user raise AdminNotFound
Personally I prefer to be explicit about
False values in conditions, but that is a moot point here. This structure is better for a function, i.e. avoiding the
for-else construct since you can simply
return from the function once you find your needle in the haystack.