Loops

Loops are a powerful building block for writing programs. They make it possible to write programs that perform repeated work without having to make copies of the same instructions (lines of code). Loops also make programs easier to read and maintain. They enable us to decide how many times to iterate while a program is running (for instance, based on a calculation or something the user enters), rather than at the time we wrote the program. In fact, it would be impossible to write most programs without loops.

Basics

The most basic loop in Python is the for-each loop:

for <var> in <expression>:
    <body>

The expression must yield a value, such as a list or a string, that can be iterated over. We will explain this construct using lists to start. For each iteration through the loop, the variable (<var>) takes on a value from the list starting at index 0 and proceeding in order.

Here is an example loop:

In [1]: l1 = [1, "abc", 5.7, [1, 3, 5]]

In [2]: for y in l1:
   ...:     print("y = " + str(y))
   ...:
y = 1
y = abc
y = 5.7
y = [1, 27.0, 5]
y = 27

Please note that ...: is the prompt that ipython3 uses when a piece of code is spread over multiple lines. It is not part of the syntax of the for loop.

Combining loops and append

It is very common to use loops to create new list from an existing list. For example, here is code that generates a new list (nl) in which the ith element of the new list is the square of the ith element of a list l.

In [3]: l = [1, 2, 3, 4, 5]

In [4]: nl = []

In [5]: for x in l:
   ...:     nl.append(x*x)
   ...:

In [6]: nl
Out[6]: [1, 4, 9, 16, 25]

The variable nl initially refers to an empty list. Every time around the loop a new entry is added to the list.

Range

At times it is useful to iterate over the index space of a list of length N (0, 1, …, N-1) rather than iterating over the contents of the list. The range function is useful for this purpose. In earlier versions of Python, the range function produced a list. In Python 3, range yields an iterator that produces a sequence of integers as needed. It can be used in three ways:

  • range(ub) which yields an iterator that produces a sequence of consecutive integer values from 0 up to, but not including, the upper bound ub
  • range(lb, ub) which yields an iterator that produces a sequence of consecutive integer values starting at the lower bound lb up to, but not incuding, the upper bound ub.
  • range(lb, ub, incr) which yields an iterator that produces a sequence of integer values starting at the lower bound lb up to, but not incuding, the upper bound ub, in increments of size incr.

Iterating over the index space of a loop

An alternate way of iterating over a list is by iterating over the index space of a list l using the expression range(len(l)). For example, we could rewrite the example above as:

In [7]: for i in range(len(l1)):
   ...:     y = l1[i]
   ...:     print("y  = " + str(y))
   ...:
y  = 1
y  = abc
y  = 5.7
y  = [1, 27.0, 5]
y  = 27

This style of iterating over lists is common in other languages, but less common in Python, where iterating as described in basics is more common.

Enumerate

Occasionally, it is useful to use both an element of a list and its index in a loop. The expression enumerate(l) yields an iterator that produces a sequence of tuples, each with an index and the value from the list at that index. For example,

In [8]: for (i, val) in enumerate(l1):
   ...:     print("l1[" + str(i) + "] = " + str(val))
   ...:
l1[0] = 1
l1[1] = abc
l1[2] = 5.7
l1[3] = [1, 3, 5]