A guide to Python "for" loops

A comprehensive guide on Python "for" loops

Python, like many programming languages, implements containers, which are collections of other objects. As such, Python provides the for statement for iterating over each element in the collection.

In this guide, we're going to cover the Python for loop. The for statement in Python is slightly different from what you might be used to in other programming languages. But in my opinion, it's easier to work with.

Many languages implement a for loop like this:

for (let i=0; i<someArray.length; i++) {
    let element = someArray[i];
    // Code to execute for each iteration
}

We have an initialization statement, conditional, and code that executes after the loop (typically to increment or decrement a counter).

But in Python, the structure of the for loop is much simpler:

for item in some_iterable:
    # Code to execute for each iteration

The goal of this guide is to provide a comprehensive overview of Python for loops. We're going to get "in the weeds" at times, and in the end, you should have a good understanding of the various uses of for loops as well as what's going on under the hood.

In this guide, you'll learn the following:

  • What is an iterable?
  • How to use the for loop to iterate over elements in an iterable.
  • How to use the break, continue, and else statements to control the flow of a for loop.
  • How to use the range function to accomplish common tasks.
1

Syntax
for <element> in <iterable>:
    # Code to execute
Example
for number in [0, 1, 2]: 
    print(number) 

Output

                                                                                                                                                                    
0
1
2

In this example, our iterable is a manually created list that includes three numbers. The word (number) immediately after the for statement is a variable that represents a single item for the current iteration. The for loop will iterate over each number in order, as you can see by the output.

2

Note: This step gets quite technical. If you're new to Python, you don't get hung up here. Understanding this material is not required to use the for loop.

An iterable is any object that can be iterated over, meaning it's capable of returning its members one at a time. It is an object that contains some collection of elements and defines either an __iter__ or __getitem__ method.

Sequences

The most common type of iterable is a sequence. You may be familiar with some of the most commonly used sequences: list, string, and tuple.

Other iterables

Some other commonly used iterables are dictionaries and generators. Dictionaries are key-value maps, and generators are functions that are used to create memory-efficient iterables. Generators are especially useful when you need to iterate over very large data sets.

Iterators

When an iterable is passed in to a built the built-in function iter, it returns an iterator. An iterator is an object representing a stream of data, and it can be passed over exactly once. An iterator implements the __next__ method retrieving the next element in the stream.

Iterables and the for statement

The for loop calls iter for us, which then generates an iterator. It passes over each element in the iterator's stream until there are no more.

See the following code for a demonstration of some of the concepts discussed above:

In [1]: my_list = [0, 1, 2]  # my_list is an "iterable"

In [2]: my_iterator = iter(my_list)  # calling iter on my_list returns an "iterator" object

In [3]: next(my_iterator)  # calling next on the iterator object returns the next element in the collection
Out[3]: 0

In [4]: next(my_iterator)                                                                                                                                                                
Out[4]: 1

In [5]: next(my_iterator)                                                                                                                                                                
Out[5]: 2

In [6]: next(my_iterator)  # StopIteration is raised when there are no more elements
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-6-26be35a80dc3> in <module>
----> 1 next(my_iterator)

StopIteration: 
3

The range type represents an immutable sequence of numbers and is used primarily in loops. Converting a range to a list is an easy way to visualize what this means.

Example
list(range(3))  # [0, 1, 2]

In the above example, the constructor is passed a single argument representing where to stop the sequence. For more advanced use cases, the constructor accepts three arguments: start, stop, and step.

Print even numbers between 10 and 20
for n in range(10, 20, 2): 
    print(n) 

Output

 
10
12
14
16
18

Notice that the start argument is inclusive, and stop is exclusive (meaning we print 10 and every number up to, but not including 20).

4

The continue statement is used skip the remainder of the code block and continue to the next iteration.

Example: Find missing fields
users = [
    {'first_name': 'Murray', 'last_name': 'Rothbard'},
    {'first_name': 'Ludwig', 'last_name': 'von Mises'},
    {'first_name': 'Friedrich', 'last_name': ''},
]

for user in users:
    if user.get('first_name') and user.get('last_name'):
        continue

    print('User is missing a field: {0}.'.format(user))

Output

User is missing a field: {'first_name': 'Friedrich', 'last_name': ''}.

The above example looks through a list of user dicts for empty fields. If it finds a user with an empty field, it prints the user dictionary. We use the continue statement to skip to the next iteration if both fields are present and not empty.

5

Break is similar to continue except that it exits the loop entirely.

Example: A simple "retry" implementation
response = None

for x in range(3):
    try:
        response = api.get_items()
        break
    except api.RequestFailed:
        continue

In the above example, we've created a basic "retry" mechanism for an API call. Using range(3) will cause exactly three iterations, but if we get a successful response, there's no need to keep trying, so we break out of the loop. If we hit a known exception (api.RequestFailed), we'll try again.

6

Many people are familiar with if/else statements, but for/else is used less frequently.

A silly example
for x in range(5): 
    continue 
else: 
    print('Loop finished.') 

Output

Loop finished.

If the loop completes normally, meaning it didn't encounter a break, then the else clause is executed.

Example: Another "retry" implementation
for x in range(3):
    try:
        response = api.get_items()
        break
    except api.RequestFailed:
        continue
else:
    raise MaxRetriesExceeded

This is a slight upgrade on the previous "retry" example. We've included an else clause that raises a MaxRetriesExceeded exception if the clause is executed. So, if we get a successful API response, we break out of the loop and continue with our program. But if the for loop completes without hitting the break (meaning the API requests failed every time), we hit the else clause and our exception is raised.

7

I hope that by now you've got a great grasp of the for loop. If you have any questions or feel like something was missing from this guide, please let me know in the comments below.