12. Iteration

12.1. Iteration Basics

Computers are ideally suited to run the same piece of code over thousands, if not millions of pieces of data. Doing the same thing over and over again is called iteration and all computer languages have instructions for iteration. The part of the code that is iterated is called a loop. The philosophy behind python's iterative commands is different to all other languages.

  • python

    list = .....
    for every item in list:
    	do something
    
  • other languages

    for item from start_number to end_number, advance a step of size
    	do something
    

In python if you create the list with range(), you have to create the whole list before you start the loop. In the 2nd method, you create one item at a time. In python, if your list is larger than can be held by the memory in your computer, then your program won't run. We'll find an example of this later when calculating π. There we'll use xrange() which generates one item at a time, rather than a list.

12.2. simple for loop

Here's example python code which iterates over a list of numbers (the '[' and ']' delineate a list).

#!/usr/bin/python

for x in [0,1,2,3,4,5]:
	print x,

Code this up as interation_1.py and check that you get reasonable output. What happens if you leave off the ',' at the end of the print statement [64] ?

The body of this loop has one instruction (the print() statement). The length of the loop isn't so obvious: no-one is pedantic about this - including the required blank line at the end, you could say that the loop is 3 lines long, or maybe 2 (the for statement and the print() statement) or maybe 1 (the print() statement).

Note

If you run this code at the python prompt (>>>), you will need a blank line after the print() statement, to let python know that the indentation has changed back to the previous level of nesting (here the left most column).

Compare this piece of code

#!/usr/bin/python

for x in [0,1,2,3,4,5]:
	print x,
	print "hello"

with this piece of code (the only change is the indentation for the print "hello" statement). Predict the output of the two pieces of code and then run the code.

#!/usr/bin/python

for x in [0,1,2,3,4,5]:
	print x,

print "hello"

Change the code in iteration_1.py to

  • initialise a variable sum to 0 before you enter the loop (note you should use descriptive variable names like sum rather than just y).
  • add x to sum each time you go through the loop, still outputting the number x across the screen in each iteration.
  • after exiting the loop, output the value of sum on new line, with some helpful text like "the sum of the numbers is".

Here's my code [65] .

Warning

x (the variable whose value is being set by the for statement) is called the control or loop variable. It's only purpose is as input to the loop statements. The loop variable should be treated as a readonly variable. (i.e. you shouldn't try to change it) i.e. do not put the control variable on the left hand side of any instructions in the loop.

DO NOT DO ANY OF THESE

x = x + 2
x = 2
x = "hello"

Changing the loop variable is unsafe programming. If you're debugging a long loop, you don't want code in the middle messing with the control variable. In some languages (fortran) you aren't allowed to change the loop variable, or it will change in unpredictable ways. (In python, in this loop above, changing x wouldn't cause any great problems, other than being unsafe programming.)

If you want to do something with the control variable, make a copy of it (with say y = x) and do whatever you need on the copy y.

12.3. another simple for loop

Using iteration_1.py as a template, write iteration_2.py to output and sum the squares of the numbers 0..5. Here's my first version [66] . Notice that the calculation of x*x is done twice. You shouldn't ever do a calculation twice - it takes too much time. If you need the result in two places, you do the calculation once and save the result in a variable. Here's a better version [67] .

Note

some new syntax: these are identical

y = y + 3
y += 3

other operators which use the same syntax are 
-=, *=, /=, %=

Modify iteration_2.py to use this new syntax. Here's my new version [68] .

12.4. iterating over a range

Most often, you aren't iterating over an irregular or random list of numbers. You usually iterate over a well behaved and ordered list. Rather than enter a list by hand, risking a mistake, python (and a few other languages) have functions to generate lists. Python's command is range() and true to python form, it behaves differently to the equivalent command in other languages.

Here's the way everyone else does it

range(start, end, [step]) #[] indicates an optional parameter, default value here is 1

range (0,10)
 0,1,2,3,4,5,6,7,8,9,10

Here's python's version

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The argument (parameter) 10, says to generate the default list (i.e. starts at 0, stepping/spacing of 1) and stop at the element before 10 (simple huh?). In this case range() produces 10 numbers, as you might expect, but see below for further developments.

For fun, try a few other sets of parameters for range().

Copy iteration_2.py to iteration_3.py and use range() to generate the list of numbers from 0..5. Here's my code [69] .

Well that was confusing, if you want to generate a list from 0..5, you need an argument of 6 for range().

Here's some more examples using range().

#as above, starting at 0
>>> range(0,10)		
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#starting at 1, ending element before 10
>>> range(1,10)		
[1, 2, 3, 4, 5, 6, 7, 8, 9]
#starting at 1, in steps of 3, ending at element before 10.
>>> range(1,10,3)	
[1, 4, 7]

Using the previous code as a template, sum the squares of all the numbers from 0..100. Then sum the squares of all the numbers from 0..100 that are divisible by 7. Here's my code [70] .

Note
End Lesson 9

12.5. the fencepost error

fencepost error (http://www.eps.mcgill.ca/jargon/jargon.html#fencepost%20error)

We've run into the fencepost error before. when I asked you to march 10h places down the alphabet from 'A'. The correct answer was 'Q', but someone got 'P'.

You want to build a fence 100ft long, in sections of 10'. How many sections of fence will you be building [71] and how many fenceposts do you need [72] ?

Same question again: if I want to sum the squares of the n consecutive integers, how many iterations (of the loop) do I need [73] ? If I want to sum the squares of integers 0..n, and how many iterations do I need [74] ?

This will fool you over and over and over, from the start of your programming career to the end. Anytime you iterate (go) from a start boundary condition, over a range, to an end boundary condition, you'll have to do a test count, to determine whether you're counting fenceposts or fences. (When you're programming, it's not always obvious whether a variable is a fence or a fencepost.) If you've got it wrong and you only have one iteration to do, the computer will think you only have to do 0 iterations. Your loop won't be executed and you'll think that there was something wrong inside the loop, that it didn't add (or whatever) your number.

12.6. while loop

First Steps to Programming (http://docs.python.org/tut/node5.html#SECTION005200000000000000000) shows a while loop.

A while loop has this structure

determine condition
while condition is true
	do a
	do b
	.
	.
	determine condition again

#code executed when condition becomes false

The while and for loops can be logically equivalent. These two produce the same output:

  • while loop

    variable = 0
    while (variable < 10):
    	variable = variable + 1
    	print variable
    
    
  • for loop

    for x in range(10)
    	print variable
    
    

The while loop requires a little more setting up, but unlike the for loop which is good for regular input, the while loop can be setup to handle just about anything (here pseudo code accepts a name)

print "enter your name followed by a carriage return"
name = ""
char = getkeystroke()	#I made this function up
# != is not equal - the loop is entered for all chars except a carriage return
# if the char is a carriage return, which instruction is executed next?
while (char != carriage return):
	char = getkeystroke()
	name += char

print name

The essential features of the while loop are

  • the while loop waits for some condition or event (above is entry of a carriage return), whose arrival is unpredictable, before exiting (or looping). When the condition or event doesn't (or does) happen, the loop exits (or loops again).
  • Some information or state accumulates during the execution of the while loop, (here the contents of the variable name) which is available on exit. This information/state/variable must be initialised before entering the while loop.