This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
We have already solved the problem of printing out a nice-looking conversion table for Celsius and Fahrenheit degrees. Nevertheless, there are usually many alternative ways to write a program that solves a specific problem. The next paragraphs explore some other possible Python constructs and programs to store numbers in lists and print out tables. The various code snippets are collected in the program file session.py.
for loop can be implemented as a
The general code
can be transformed to this
for element in somelist: <process element>
In particular, the example involving the printout of a table of Celsius and Fahrenheit degrees can be implemented as follows in terms of a
index = 0 while index < len(somelist): element = somelist[index] <process element> index += 1
Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40] index = 0 print ' C F' while index < len(Cdegrees): C = Cdegrees[index] F = (9.0/5)*C + 32 print '%5d %5.1f' % (C, F) index += 1
It is tedious to write the many elements in the
Cdegrees in the
previous programs. We should use a loop to automate the construction of
Cdegrees list. The
range construction is particularly
useful in this regard:
0, 1, 2, ..., n-1.
range(start, stop, step)generates a sequence if integers
start+2*step, and so on up to, but not including,
stop. For example,
range(2, 8, 3)returns 2 and 5 (and not 8), while
range(1, 11, 2)returns 1, 3, 5, 7, 9.
range(start, stop)is the same as
range(start, stop, 1).
forloop over integers are written as
We can use this construction to create a
for i in range(start, stop, step): ...
Cdegreeslist of the values \( -20, -15, \ldots, 40 \):
Note that the upper limit must be greater than
Cdegrees =  for C in range(-20, 45, 5): Cdegrees.append(C) # or just Cdegrees = range(-20, 45, 5)
40to ensure that
40is included in the range of integers.
Suppose we want to create
Cdegrees as \( -10, -7.5, -5, \ldots, 40 \).
This time we cannot use
range directly, because
range can only
create integers and we have decimal degrees such as \( -7.5 \) and \( 1.5 \).
In this more general case, we introduce an integer counter \( i \) and
generate the \( C \) values by the formula \( C=-10 + i\cdot 2.5 \) for
\( i=0,1,\ldots, 20 \). The following Python code implements this task:
Cdegrees =  for i in range(0, 21): C = -10 + i*2.5 Cdegrees.append(C)
Instead of iterating over a list directly with the construction
we can equivalently iterate of the list indices and index the list inside the loop:
for element in somelist: ...
for i in range(len(somelist)): element = somelist[i] ...
len(somelist)returns the length of
somelistand the largest legal index is
len(somelist)-1, because indices always start at 0,
range(len(somelist))will generate all the correct indices:
1, \( \ldots \),
Programmers coming from other languages, such as Fortran,
C, C++, Java, and C#, are very much used to
for loops with
integer counters and usually
tend to use
for i in range(len(somelist)) and work with
somelist[i] inside the loop. This might be necessary or convenient,
but if possible, Python programmers are encouraged to use
for element in somelist, which is more elegant to read.
Iterating over loop indices is useful when we need to process two
lists simultaneously. As an example, we first create two
Fdegrees lists, and then we make a list to write out a table
Fdegrees as the two columns of the table.
Iterating over a loop index is convenient in the final list:
Cdegrees =  n = 21 C_min = -10 C_max = 40 dC = (C_max - C_min)/float(n-1) # increment in C for i in range(0, n): C = -10 + i*dC Cdegrees.append(C) Fdegrees =  for C in Cdegrees: F = (9.0/5)*C + 32 Fdegrees.append(F) for i in range(len(Cdegrees)): C = Cdegrees[i] F = Fdegrees[i] print '%5.1f %5.1f' % (C, F)
Instead of appending new elements to the lists, we can start with lists
of the right size, containing zeros, and then index the lists to fill
in the right values. Creating a list of length
n consisting of zeros
(for instance) is done by
With this construction, the program above can use
somelist = *n
forloops over indices everywhere:
Note that we need the construction
n = 21 C_min = -10 C_max = 40 dC = (C_max - C_min)/float(n-1) # increment in C Cdegrees = *n for i in range(len(Cdegrees)): Cdegrees[i] = -10 + i*dC Fdegrees = *n for i in range(len(Cdegrees)): Fdegrees[i] = (9.0/5)*Cdegrees[i] + 32 for i in range(len(Cdegrees)): print '%5.1f %5.1f' % (Cdegrees[i], Fdegrees[i])
*nto create a list of the right length, otherwise the index
[i]will be illegal.
We have two seemingly alternative ways to traverse a list, either a
loop over elements or over indices. Suppose we want to change the
Cdegrees list by adding 5 to all elements. We could try
but this loop leaves
for c in Cdegrees: c += 5
works as intended. What is wrong with the first loop? The problem is that
for i in range(len(Cdegrees)): Cdegrees[i] += 5
cis an ordinary variable, which refers to a list element in the loop, but when we execute
c += 5, we let
crefer to a new
c+5). This object is never inserted in the list. The first two passes of the loop are equivalent to
c = Cdegrees # automatically done in the for statement c += 5 c = Cdegrees # automatically done in the for statement c += 5
ccan only be used to read list elements and never to change them. Only an assignment of the form
can change a list element.
Cdegrees[i] = ...
There is a way of traversing a list where we get both the index and an element in each pass of the loop:
This loop also adds 5 to all elements in the list.
for i, c in enumerate(Cdegrees): Cdegrees[i] = c + 5
Because running through a list and for each element creating a new element in another list is a frequently encountered task, Python has a special compact syntax for doing this, called list comprehension. The general syntax reads
newlist = [E(e) for e in list]
E(e)represents an expression involving element
e. Here are three examples:
List comprehensions are recognized as a
Cdegrees = [-5 + i*0.5 for i in range(n)] Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] C_plus_5 = [C+5 for C in Cdegrees]
forloop inside square brackets and will be frequently exemplified throughout the document.
We may use the
Fdegrees lists to
make a table. To this end, we need to traverse both arrays.
for element in list construction is not suitable in this
case, since it extracts elements from one list only.
A solution is to use a
for loop over the integer indices so that
we can index both lists:
It happens quite frequently that two or more lists need to be traversed simultaneously. As an alternative to the loop over indices, Python offers a special nice syntax that can be sketched as
for i in range(len(Cdegrees)): print '%5d %5.1f' % (Cdegrees[i], Fdegrees[i])
for e1, e2, e3, ... in zip(list1, list2, list3, ...): # work with element e1 from list1, element e2 from list2, # element e3 from list3, etc.
zipfunction turns \( n \) lists (
list1, list2, list3, ...) into one list of \( n \)-tuples, where each \( n \)-tuple
(e1,e2,e3,...)has its first element (
e1) from the first list (
list1), the second element (
e2) from the second list (
list2), and so forth. The loop stops when the end of the shortest list is reached. In our specific case of iterating over the two lists
Fdegrees, we can use the
It is considered more Pythonic to iterate over list elements, here
for C, F in zip(Cdegrees, Fdegrees): print '%5d %5.1f' % (C, F)
F, rather than over list indices as in the
for i in range(len(Cdegrees))construction.