Loops in Python

Introduction

A programming language typically consists of several types of basic elements, such as assignments, conditionals, and loops. The idea behind a loop is to repeat a segment of code that is in the body of the loop. Different kinds of loops are common. For example, loops will run:

  • while a specified condition is true (i.e. while the condition is met, do something)
  • until a certain condition is met (i.e. do something until the condition is met)
  • for a fixed number of steps (iterations) (i.e. for x iterations, do something)
  • as an endless loop and exit/break on condition (while condition_1 is true do something and exit on condition_2)

Python offers a variety of constructs to perform loops. This article presents them and gives advice on their specific usage. Furthermore, we will also have a look at the performance of each looping construct in your Python code. It might be surprising to you.

Loop Constructs Supported by Python

Python supports a partial number of the constructs named above, plus it offers unique extensions to the types we have mentioned.

Basic while Loops

while condition:
    statements

As long as the condition is met, all the statements in the body of the while loop are executed at least once. After each time the body statement is executed, the condition is re-evaluated. Here is an example of an actual while loop:

# Listing 1

fruits = ["banana", "apple", "orange", "kiwi"]
position = 0
while position < len(fruits):
    print(fruits[position])
    position = position + 1

print("Reached the end of the list")

This code will output one list element after the next:

banana
apple
orange
kiwi
Reached the end of the list

while Loops with an else Clause

This construct is specific to the Python language, and quite helpful:

while condition:
    statements
else:
    statements

This while loop acts similar to the regular while loop as introduced before. The statements in the else section are executed as soon as the condition is no longer true. For example, when the end of a list is reached, as in our previous example. You may interpret it as "then" when the condition of the loop is no longer met:

# Listing 2

fruits = ["banana", "apple", "orange", "kiwi"]
position = 0
while position < len(fruits):
    print(fruits[position])
    position = position + 1
else:
    print("Reached the end of the list")

This will output one list element after the next, plus the additional text from the print statement in the else clause:

banana
apple
orange
kiwi
Reached the end of the list

This kind of loop with an else clause is handy in order to output messages or execute statements in case your condition fails.

Note: One important thing to note is that the else clause is not executed if you break out of the while loop or if an error is thrown from within the while loop.

Infinite while Loops

Infinite loops are always taught as being critical components and to be avoided if the break condition is a complicated matter. Although there are cases in which infinite loops help you to write code in an elegant way.

Here are just a few use-cases of infinite loops:

  • Devices that try to keep network connections active, like wireless access points
  • Clients that try to constantly exchange data with a host system, like a network-based file system (NFS or Samba/CIFS)
  • Game loops for drawing and updating your game state
while True:
    if condition:
        break
    statements

Keep in mind that the statements in the body of an endless loop are run at least once. That's why I recommend writing the break condition as the very first statement after the head of the loop if possible. Following our example code, an infinite loop looks as follows:

# Listing 3

fruits = ["banana", "apple", "orange", "kiwi"]
position = 0
while True:
    if position >= len(fruits):
        break

    print(fruits[position])
    position = position + 1

print("Reached the end of the list")

for Loops with an Iterator

The typical way to work with lists in a loop in Python is with the for loop, in combination with an iterator:

for temp_var in sequence:
    statements

This simplifies the Python code for processing our list:

# Listing 4

fruits = ["banana", "apple", "orange", "kiwi"]
for food in fruits:
    print(food)

print("Reached the end of the list")

In this type of looping construct, the Python interpreter handles iterating over the list and takes care that the loop does not run outside the range of the list. Keep in mind that the statements in the body of the loop are run once for every element in the list - no matter if it is just a single element or twenty thousand.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

In case the list is empty, the statements in the body of the loop are not executed.

Note: Changing the list in terms of adding or removing elements within the for loop may confuse the Python interpreter and cause problems, so be careful!

for Loops with Iterator and else Clause

Similar to the while loop, Python also offers an else statement for the for loop. It works similarly and can be interpreted as "then", just as before. The pseudocode looks as follows:

for temp_var in sequence:
    statements
else:
    statements

Using this keyword, our code changes as follows:

# Listing 5

fruits = ["banana", "apple", "orange", "kiwi"]
for food in fruits:
    print(food)
else:
    print("Reached the end of the list")

Unsupported Loop Constructs

As stated at the beginning, there are many different loop styles. However, Python does not support them all. For example, Python does not support a do-until or a foreach loop construct, as possibly known from PHP.

Note: Such cases are solved using Python's in operator that creates quite sexy code if you're familiar with it.

For example, a foreach loop is constructed in the for <variable> in <collection> fashion. That creates the exact same logic as the foreach loop, but has a slightly different syntax. You may have noticed that this is the syntax we've used in our examples above.

Which Loop to Choose?

In general, the while <condition> loops require a condition to be specified before the loop's statements. This may lead to the case that the statements in the body of the loop are never executed. Also, it is not always clear how many times the loop will execute for while loops. On the other hand, for loops are more suited to use an iterator that helps iterate over the elements of a data structure, like an array.

It is recommended to use a for loop if you have a set number of elements to iterate over, or if you need to run code a fixed number of times. In contrast, a while loop is better when you have a boolean expression to evalutate, and not a list of elements to loop over.

Improving the Quality of your Code

Many younger programmers are more susceptible to writing inefficient code, largely because they've grown up in a time in which nobody has to think about memory or processing capacity - we just have plenty of it available in modern computers. Instead, more experienced (aka "older") developers are more prone to optimize their code as much as possible and may remember counting CPU instructions and the number of memory slots that are in use.

So what does quality mean today? In terms of efficiency, it means writing code that will take the least amount of memory and CPU time possible. Firstly, with today's interpreters, run-times, frameworks, and other abstractions, it is quite difficult to calculate that properly. And secondly, it is always a trade-off between these two measures. The key questions are, how often will this code be in use and how much time shall we spend on optimizing it to win a few microseconds of CPU time?

As an example, let's take a look at a for loop iterating over a list. Usually, we write it as follows:

# Listing 6

for entry in range(0, 3):
    print(entry)

This outputs the values 0, 1, and 2. The range() method creates the iterable [0, 1, 2] every time the head of the loop is evaluated. Therefore it is better to write it as follows:

# Listing 7

entryRange = range(0, 3)
for entry in entryRange:
    print(entry)

While this may not seem like huge optimization for the given example, consider if the range was from 0 to 1,000,000 or more. As our list grows larger, we save more time and our code executes faster.

Furthermore, these statements can be expressed as a while loop:

# Listing 8

entryRange = range(0, 3)
index = 0
while index < len(entryRange):
    print(entryRange[index])
    index = index + 1

And by this point, it seems a bit pointless to even use the range() function. Instead, we might as well just use a constant for the conditional and index as a counter for the conditional and printing:

index = 0
while index < 3:
    print(index)
    index = index + 1

Note: Small optimizations like these can provide small performance improvements for your loops, especially as the number of iterations becomes very large.

Performance Tests

So far, we spoke about loop code and how to write it properly. A performance test may help to bring in some light. The idea is kindly borrowed from an interesting blog article by Ned Batchelder.

In use is the perf tool that does performance tests for program code that is executed. The basic call is perf stat program whereas stat abbreviates statistics and the program is the call we would like to evaluate. To test our loop variants these calls were done:

perf stat python3 while-1.py
perf stat python3 while-2.py
perf stat python3 while-3.py
perf stat python3 for-4.py
perf stat python3 for-5.py
perf stat python3 for-6.py
perf stat python3 for-7.py
perf stat python3 while-8.py

These results are the average based on 10 runs due to load differences in the Linux kernel. The following table shows the results:

Topic Listing 1 Listing 2 Listing 3 Listing 4 Listing 5
task clock (msec) 20.160077 18.535264 15.975387 15.427334 15.503672
context switches 10 11 10 13 10
cpu migrations 0 0 2 1 1
page faults 851 849 855 848 851
cycles 41,915,010 44,938,837 44,403,696 42,983,392 42,489,206
instructions 46,833,820 46,803,187 46,926,383 46,596,667 46,701,350

For the Listings 6-8 it looks as follows:

Topic Listing 6 Listing 7 Listing 8
task clock (msec) 16.480322 18.193437 15.734627
context switches 9 11 11
cpu migrations 0 0 1
page faults 850 851 853
cycles 42,424,639 42,569,550 43,038,837
instructions 46,703,893 46,724,190 46,695,710

Conclusion

Python offers different ways to repeat actions and write loops. There are variants per specific use case. Our tests have shown that the loops are in the same dimension with few differences, and the optimization of the Python interpreter is quite good.

Last Updated: February 17th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Frank HofmannAuthor

IT developer, trainer, and author. Coauthor of the Debian Package Management Book (http://www.dpmb.org/).

Project

Building Your First Convolutional Neural Network With Keras

# python# artificial intelligence# machine learning# tensorflow

Most resources start with pristine datasets, start at importing and finish at validation. There's much more to know. Why was a class predicted? Where was...

David Landup
David Landup
Details
Course

Data Visualization in Python with Matplotlib and Pandas

# python# pandas# matplotlib

Data Visualization in Python with Matplotlib and Pandas is a course designed to take absolute beginners to Pandas and Matplotlib, with basic Python knowledge, and...

David Landup
David Landup
Details

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms