Simple Use of for-else in Python

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 UserNotFound exception.

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 for-else

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 break‘s.

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 True and 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.

Advertisements

Add Your Thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s