Loop control statements

Introduction

In this chapter, you will learn how to make the computer execute a group of statements over and over as long as certain criterion holds. The group of statements being executed repeatedly is called a loop. There are two loop statements in Python: for and while. We will discuss the difference between these statements later in the chapter, but first let us look at an example of a loop in the real world.

A petrol attendant performs the following actions when serving a customer:

  1. greet customer

  2. ask for required type of petrol and amount

  3. ask whether customer needs other services

  4. ask for required amount of money

  5. give money to cashier

  6. wait for change and receipt

  7. give change and receipt to customer

  8. say thank you and goodbye

A petrol attendant performs these steps for each customer, but he does not follow them when there is no customer to serve. He also only performs them when it is his shift. If we were to write a computer program to simulate this behaviour, it would not be enough just to provide the steps and ask the computer to repeat them over and over. We would also need to tell it when to stop executing them.

There are two major kinds of programming loops: counting loops and event-controlled loops.

In a counting loop, the computer knows at the beginning of the loop execution how many times it needs to execute the loop. In Python, this kind of loop is defined with the for statement, which executes the loop body for every item in some list.

In an event-controlled loop, the computer stops the loop execution when a condition is no longer true. In Python, you can use the while statement for this – it executes the loop body while the condition is true. The while statement checks the condition before performing each iteration of the loop. Some languages also have a loop statement which performs the check after each iteration, so that the loop is always executed at least once. Python has no such construct, but we will see later how you can simulate one.

Counting loops are actually subset of event-control loop - the loop is repeated until the required number of iterations is reached.

If you wanted to get from Cape Town to Camps Bay, what loop algorithm would you use? If you started by putting your car on the road to Camps Bay, you could:

  • drive for exactly 15 minutes. After 15 minutes, stop the car and get out.

  • drive for exactly 8km. After 8km, stop the car and get out.

  • drive as long as you are not in Camps Bay. When you arrive, stop the car and get out.

The first two algorithms are based on counting – the first counts time, and the second counts distance. Neither of these algorithms guarantees that you will arrive in Camps Bay. In the first case, you might hit heavy traffic or none at all, and either fall short of or overshoot your desired destination. In the second case, you might find a detour and end up nowhere near Camps Bay.

The third algorithm is event-controlled. You carry on driving as long as you are not at the beach. The condition you keep checking is am I at the beach yet?.

Many real-life activities are event-controlled. For example, you drink as long as you are thirsty. You read the newspaper as long as you are interested. Some activities are based on multiple events – for example, a worker works as long as there is work to do and the time is not 5pm.

The while statement

Python’s event-controlled loop statement is the while statement. You should use it when you don’t know beforehand how many times you will have to execute the body of the loop. The while-body keeps repeating as long as the condition is true. Here’s a flow control diagram for the while statement:

The loop consists of three important parts: the initialisation, the condition, and the update. In the initialisation step, you set up the variable which you’re going to use in the condition. In the condition step, you perform a test on the variable to see whether you should terminate the loop or execute the body another time. Then, after each successfully completed execution of the loop body, you update your variable.

Note that the condition is checked before the loop body is executed for the first time – if the condition is false at the start, the loop body will never be executed at all.

Here is a simple Python example which adds the first ten integers together:

total = 0
i = 1

while i <=10:
    total += i
    i += 1

The variable used in the loop condition is the number i, which you use to count the integers from 1 to 10. First you initialise this number to 1. In the condition, you check whether i is less than or equal to 10, and if this is true you execute the loop body. Then, at the end of the loop body, you update i by incrementing it by 1.

It is very important that you increment i at the end. If you did not, i would always be equal to 1, the condition would always be true, and your program would never terminate – we call this an infinite loop. Whenever you write a while loop, make sure that the variable you use in your condition is updated inside the loop body!

Here are a few common errors which might result in an infinite loop:

x = 0
while x < 3:
    y += 1 # wrong variable updated

product = 1
count = 1

while count <= 10:
    product *= count
    # forgot to update count

x = 0
while x < 5:
    print(x)
x += 1 # update statement is indented one level too little, so it's outside the loop body

x = 0
while x != 5:
    print(x)
    x += 2 # x will never equal 5, because we are counting in even numbers!

You might be wondering why the Python interpreter cannot catch infinite loops. This is known as the halting problem. It is impossible for a computer to detect all possible infinite loops in another program. It is up to the programmer to avoid infinite loops.

In many of the examples above, we are counting to a predetermined number, so it would really be more appropriate for us to use a for loop (which will be introduced in the next section) – that is the loop structure which is more commonly used for counting loops. Here is a more realistic example:

# numbers is a list of numbers -- we don't know what the numbers are!

total = 0
i = 0

while i < len(numbers) and total < 100:
    total += numbers[i]
    i +=1

Here we add up numbers from a list until the total reaches 100. We don’t know how many times we will have to execute the loop, because we don’t know the values of the numbers. Note that we might reach the end of the list of numbers before the total reaches 100 – if we try to access an element beyond the end of the list we will get an error, so we should add a check to make sure that this doesn’t happen.

Exercise 1

  1. Write a program which uses a while loop to sum the squares of integers (starting from 1) until the total exceeds 200. Print the final total and the last number to be squared and added.

  2. Write a program which keeps prompting the user to guess a word. The user is allowed up to ten guesses – write your code in such a way that the secret word and the number of allowed guesses are easy to change. Print messages to give the user feedback.

The for statement

Python’s other loop statement is the for statement. You should use it when you need to do something for some predefined number of steps. Before we look at Python’s for loop syntax, we will briefly look at the way for loops work in other languages.

Here is an example of a for loop in Java:

for (int count = 1; count <= 8; count++) {
    System.out.println(count);
}

You can see that this kind of for loop has a lot in common with a while loop – in fact, you could say that it’s just a special case of a while loop. The initialisation step, the condition and the update step are all defined in the section in parentheses on the first line.

for loops are often used to perform an operation on every element of some kind of sequence. If you wanted to iterate over a list using the classic-style for loop, you would have to count from zero to the end of the list, and then access each list element by its index.

In Python, for loops make this use case simple and easy by allowing you to iterate over sequences directly. Here is an example of a for statement which counts from 1 to 8:

for i in range(1, 9):
    print(i)

As we saw in the previous chapter, range is an immutable sequence type used for ranges of integers – in this case, the range is counting from 1 to 8. The for loop will step through each of the numbers in turn, performing the print action for each one. When the end of the range is reached, the for loop will exit.

You can use for to iterate over other kinds of sequences too. You can iterate over a list of strings like this:

pets = ["cat", "dog", "budgie"]

for pet in pets:
    print(pet)

At each iteration of the loop, the next element of the list pets is assigned to the variable pet, which you can then access inside the loop body. The example above is functionally identical to this:

for i in range(len(pets)): # i will iterate over 0, 1 and 2
    pet = pets[i]
    print(pet)

That is similar to the way for loops are written in, for example, Java. You should avoid doing this, as it’s more difficult to read, and unnecessarily complex. If for some reason you need the index inside the loop as well as the list element itself, you can use the enumerate function to number the elements:

for i, pet in enumerate(pets):
    pets[i] = pet.upper() # rewrite the list in all caps

Like range, enumerate also returns an iterator – each item it generates is a tuple in which the first value is the index of the element (starting at zero) and the second is the element itself. In the loop above, at each iteration the value of the index is assigned to the variable i, and the element is assigned to the variable pet, as before.

Why couldn’t we just write pet = pet.upper()? That would just assign a new value to the variable pet inside the loop, without changing the original list.

This brings us to a common for loop pitfall: modifying a list while you’re iterating over it. The example above only modifies elements in-place, and doesn’t change their order around, but you can cause all kinds of errors and unintended behaviour if you insert or delete list elements in the middle of iteration:

numbers = [1, 2, 2, 3]

for i, num in enumerate(numbers):
    if num == 2:
        del numbers[i]

print(numbers) # oops -- we missed one, because we shifted the elements around while we were iterating!

Sometimes you can avoid this by iterating over a copy of the list instead, but it won’t help you in this case – as you delete elements from the original list, it will shrink, so the indices from the unmodified list copy will soon exceed the length of the modified list and you will get an error. In general, if you want to select a subset of elements from a list on the basis of some criterion, you should use a list comprehension instead. We will look at them at the end of this chapter.

Exercise 2

  1. Write a program which sums the integers from 1 to 10 using a for loop (and prints the total at the end).

  2. Can you think of a way to do this without using a loop?

  3. Write a program which finds the factorial of a given number. E.g. 3 factorial, or 3! is equal to 3 x 2 x 1; 5! is equal to 5 x 4 x 3 x 2 x 1, etc.. Your program should only contain a single loop.

  4. Write a program which prompts the user for 10 floating-point numbers and calculates their sum, product and average. Your program should only contain a single loop.

  5. Rewrite the previous program so that it has two loops – one which collects and stores the numbers, and one which processes them.

Nested loops

We saw in the previous chapter that we can create multi-dimensional sequences – sequences in which each element is another sequence. How do we iterate over all the values of a multi-dimensional sequence? We need to use loops inside other loops. When we do this, we say that we are nesting loops.

Consider the timetable example from the previous chapter – let us say that the timetable contains seven days, and each day contains 24 time slots. Each time slot is a string, which is empty if there is nothing scheduled for that slot. How can we iterate over all the time slots and print out all our scheduled events?

# first let's define weekday names
WEEKDAYS = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')

# now we iterate over each day in the timetable
for day in timetable:
    # and over each timeslot in each day
    for i, event in enumerate(day):
        if event: # if the slot is not an empty string
            print("%s at %02d:00 -- %s" % (WEEKDAYS[day], i, event))

Note that we have two for loops – the inner loop will be executed once for every step in the outer loop’s iteration. Also note that we are using the enumerate function when iterating over the days – because we need both the index of each time slot (so that we can print the hour) and the contents of that slot.

You may have noticed that we look up the name of the weekday once for every iteration of the inner loop – but the name only changes once for every iteration of the outer loop. We can make our loop a little more efficient by moving this lookup out of the inner loop, so that we only perform it seven times and not 168 times!

for day in timetable:
    day_name = WEEKDAYS[day]
    for i, event in enumerate(day):
        if event:
            print("%s at %02d:00 -- %s" % (day_name, i, event))

This doesn’t make much difference when you are looking up a value in a short tuple, but it could make a big difference if it were an expensive, time-consuming calculation and you were iterating over hundreds or thousands of values.

Exercise 3

  1. Write a program which uses a nested for loop to populate a three-dimensional list representing a calendar: the top-level list should contain a sub-list for each month, and each month should contain four weeks. Each week should be an empty list.

  2. Modify your code to make it easier to access a month in the calendar by a human-readable month name, and each week by a name which is numbered starting from 1. Add an event (in the form of a string description) to the second week in July.

Iterables, iterators and generators

In Python, any type which can be iterated over with a for loop is an iterable. Lists, tuples, strings and dicts are all commonly used iterable types. Iterating over a list or a tuple simply means processing each value in turn.

Sometimes we use a sequence to store a series of values which don’t follow any particular pattern: each value is unpredictable, and can’t be calculated on the fly. In cases like this, we have no choice but to store each value in a list or tuple. If the list is very large, this can use up a lot of memory.

What if the values in our sequence do follow a pattern, and can be calculated on the fly? We can save a lot of memory by calculating values only when we need them, instead of calculating them all up-front: instead of storing a big list, we can store only the information we need for the calculation.

Python has a lot of built-in iterable types that generate values on demand – they are often referred to as generators. We have already seen some examples, like range and enumerate. You can mostly treat a generator just like any other sequence if you only need to access its elements one at a time – for example, if you use it in a for loop:

# These two loops will do exactly the same thing:

for i in (1, 2, 3, 4, 5):
    print(i)

for i in range(1, 6):
    print(i)

You may notice a difference if you try to print out the generator’s contents – by default all you will get is Python’s standard string representation of the object, which shows you the object’s type and its unique identifier. To print out all the values of generator, we need to convert it to a sequence type like a list, which will force all of the values to be generated:

# this will not be very helpful
print(range(100))

# this will show you all the generated values
print(list(range(100)))

You can use all these iterables almost interchangeably because they all use the same interface for iterating over values: every iterable object has a method which can be used to return an iterator over that object. The iterable and the iterator together form a consistent interface which can be used to loop over a sequence of values – whether those values are all stored in memory or calculated as they are needed:

  • The iterable has a method for accessing an item by its index. For example, a list just returns the item which is stored in a particular position. A range, on the other hand, calculates the integer in the range which corresponds to a particular index.

  • The iterator “keeps your place” in the sequence, and has a method which lets you access the next element. There can be multiple iterators associated with a single iterable at the same time – each one in a different place in the iteration. For example, you can iterate over the same list in both levels of a nested loop – each loop uses its own iterator, and they do not interfere with each other:

    animals = ['cat', 'dog', 'fish']
    
    for first_animal in animals:
        for second_animal in animals:
            print("Yesterday I bought a %s. Today I bought a %s." % (first_animal, second_animal))
    

We will look in more detail at how these methods are defined in a later chapter, when we discuss writing custom objects. For now, here are some more examples of built-in generators defined in Python’s itertools module:

# we need to import the module in order to use it
import itertools

# unlike range, count doesn't have an upper bound, and is not restricted to integers
for i in itertools.count(1):
    print(i) # 1, 2, 3....

for i in itertools.count(1, 0.5):
    print(i) # 1.0, 1.5, 2.0....

# cycle repeats the values in another iterable over and over
for animal in itertools.cycle(['cat', 'dog']):
    print(animal) # 'cat', 'dog', 'cat', 'dog'...

# repeat repeats a single item
for i in itertools.repeat(1): # ...forever
    print(i) # 1, 1, 1....

for i in itertools.repeat(1, 3): # or a set number of times
    print(i) # 1, 1, 1

# chain combines multiple iterables sequentially
for i in itertools.chain(numbers, animals):
    print(i) # print all the numbers and then all the animals

Some of these generators can go on for ever, so if you use them in a for loop you will need some other check to make the loop terminate!

There is also a built-in function called zip which allows us to combine multiple iterables pairwise. It also outputs a generator:

for i in zip((1, 2, 3), (4, 5, 6)):
    print(i)

for i in zip(range(5), range(5, 10), range(10, 15)):
    print(i)

The combined iterable will be the same length as the shortest of the component iterables – if any of the component iterables are longer than that, their trailing elements will be discarded.

Exercise 4

  1. Create a tuple of month names and a tuple of the number of days in each month (assume that February has 28 days). Using a single for loop, construct a dictionary which has the month names as keys and the corresponding day numbers as values.

  2. Now do the same thing without using a for loop.

Comprehensions

Suppose that we have a list of numbers, and we want to build a new list by doubling all the values in the first list. Or that we want to extract all the even numbers from a list of numbers. Or that we want to find and capitalise all the animal names in a list of animal names that start with a vowel. We can do each of these things by iterating over the original list, performing some kind of check on each element in turn, and appending values to a new list as we go:

numbers = [1, 5, 2, 12, 14, 7, 18]

doubles = []
for number in numbers:
    doubles.append(2 * number)

even_numbers = []
for number in numbers:
    if number % 2 == 0:
        even_numbers.append(number)

animals = ['aardvark', 'cat', 'dog', 'opossum']

vowel_animals = []
for animal in animals:
    if animal[0] in 'aeiou':
        vowel_animals.append(animal.title())

That’s quite an unwieldy way to do something very simple. Fortunately, we can rewrite simple loops like this to use a cleaner and more readable syntax by using comprehensions.

A comprehension is a kind of filter which we can define on an iterable based on some condition. The result is another iterable. Here are some examples of list comprehensions:

doubles = [2 * number for number in numbers]
even_numbers = [number for number in numbers if number % 2 == 0]
vowel_animals = [animal.title() for animal in animals if animal[0] in 'aeiou']

The comprehension is the part written between square brackets on each line. Each of these comprehensions results in the creation of a new list object.

You can think of the comprehension as a compact form of for loop, which has been rearranged slightly.

  • The first part (2 * number or number or animal.title()) defines what is going to be inserted into the new list at each step of the loop. This is usually some function of each item in the original iterable as it is processed.

  • The middle part (for number in numbers or for animal in animals) corresponds to the first line of a for loop, and defines what iterable is being iterated over and what variable name each item is given inside the loop.

  • The last part (nothing or if number % 2 == 0 or if animal[0] in 'aeiou') is a condition which filters out some of the original items. Only items for which the condition is true will be processed (as described in the first part) and included in the new list. You don’t have to include this part – in the first example, we want to double all the numbers in the original list.

List comprehensions can be used to replace loops that are a lot more complicated than this – even nested loops. The more complex the loop, the more complicated the corresponding list comprehension is likely to be. A long and convoluted list comprehension can be very difficult for someone reading your code to understand – sometimes it’s better just to write the loop out in full.

The final product of a comprehension doesn’t have to be a list. You can create dictionaries or generators in a very similar way – a generator expression uses round brackets instead of square brackets, a set comprehension uses curly brackets, and a dict comprehension uses curly brackets and separates the key and the value using a colon:

numbers = [1, 5, 2, 12, 14, 7, 18]

# a generator comprehension
doubles_generator = (2 * number for number in numbers)

# a set comprehension
doubles_set = {2 * number for number in numbers}

# a dict comprehension which uses the number as the key and the doubled number as the value
doubles_dict = {number: 2 * number for number in numbers}

If your generator expression is a parameter being passed to a function, like sum, you can leave the round brackets out:

sum_doubles = sum(2 * number for number in numbers)

Note

dict and set comprehensions were introduced in Python 3. In Python 2 you have to create a list or generator instead and convert it to a set or a dict yourself.

Exercise 5

  1. Create a string which contains the first ten positive integers separated by commas and spaces. Remember that you can’t join numbers – you have to convert them to strings first. Print the output string.

  2. Rewrite the calendar program from exercise 3 using nested comprehensions instead of nested loops. Try to append a string to one of the week lists, to make sure that you haven’t reused the same list instead of creating a separate list for each week.

  3. Now do something similar to create a calendar which is a list with 52 empty sublists (one for each week in the whole year). Hint: how would you modify the nested for loops?

The break and continue statements

break

Inside the loop body, you can use the break statement to exit the loop immediately. You might want to test for a special case which will result in immediate exit from the loop. For example:

x = 1

while x <= 10:
    if x == 5:
        break

    print(x)
    x += 1

The code fragment above will only print out the numbers 1 to 4. In the case where x is 5, the break statement will be encountered, and the flow of control will leave the loop immediately.

continue

The continue statement is similar to the break statement, in that it causes the flow of control to exit the current loop body at the point of encounter – but the loop itself is not exited. For example:

for x in range(1, 10 + 1): # this will count from 1 to 10
    if x == 5:
        continue

    print(x)

This fragment will print all the numbers from 1 to 10 except 5. In the case where x is 5, the continue statement will be encountered, and the flow of control will leave that loop body – but then the loop will continue with the next element in the range.

Note that if we replaced break with continue in the first example, we would get an infinite loop – because the continue statement would be triggered before x could be updated. x would stay equal to 5, and keep triggering the continue statement, for ever!

Using break to simulate a do-while loop

Recall that a while loop checks the condition before executing the loop body for the first time. Sometimes this is convenient, but sometimes it’s not. What if you always need to execute the loop body at least once?

age = input("Please enter your age: ")
while not valid_number(age): # let's assume that we've defined valid_number elsewhere
    age = input("Please enter your age: ")

We have to ask the user for input at least once, because the condition depends on the user input – so we have to do it once outside the loop. This is inconvenient, because we have to repeat the contents of the loop body – and unnecessary repetition is usually a bad idea. What if we want to change the message to the user later, and forget to change it in both places? What if the loop body contains many lines of code?

Many other languages offer a structure called a do-while loop, or a repeat-until loop, which checks the condition after executing the loop body. That means that the loop body will always be executed at least once. Python doesn’t have a structure like this, but we can simulate it with the help of the break statement:

while True:
    age = input("Please enter your age: ")
    if valid_number(age):
        break

We have moved the condition inside the loop body, and we can check it at the end, after asking the user for input. We have replaced the condition in the while statement with True – which is, of course, always true. Now the while statement will never terminate after checking the condition – it can only terminate if the break statement is triggered.

This trick can help us to make this particular loop use case look better, but it has its disadvantages. If we accidentally leave out the break statement, or write the loop in such a way that it can never be triggered, we will have an infinite loop! This code can also be more difficult to understand, because the actual condition which makes the loop terminate is hidden inside the body of the loop. You should therefore use this construct sparingly. Sometimes it’s possible to rewrite the loop in such a way that the condition can be checked before the loop body and repetition is avoided:

age = None # we can initialise age to something which is not a valid number
while not valid_number(age): # now we can use the condition before asking the user anything
    age = input("Please enter your age: ")

Exercise 6

  1. Write a program which repeatedly prompts the user for an integer. If the integer is even, print the integer. If the integer is odd, don’t print anything. Exit the program if the user enters the integer 99.

  2. Some programs ask the user to input a variable number of data entries, and finally to enter a specific character or string (called a sentinel) which signifies that there are no more entries. For example, you could be asked to enter your PIN followed by a hash (#). The hash is the sentinel which indicates that you have finished entering your PIN.

    Write a program which averages positive integers. Your program should prompt the user to enter integers until the user enters a negative integer. The negative integer should be discarded, and you should print the average of all the previously entered integers.

  3. Implement a simple calculator with a menu. Display the following options to the user, prompt for a selection, and carry out the requested action (e.g. prompt for two numbers and add them). After each operation, return the user to the menu. Exit the program when the user selects 0. If the user enters a number which is not in the menu, ignore the input and redisplay the menu. You can assume that the user will enter a valid integer:

    -- Calculator Menu --
    0. Quit
    1. Add two numbers
    2. Subtract two numbers
    3. Multiply two numbers
    4. Divide two numbers
    

Using loops to simplify code

We can use our knowledge of loops to simplify some kinds of redundant code. Consider this example, in which we prompt a user for some personal details:

name = input("Please enter your name: ")
surname = input("Please enter your surname: ")
# let's store these as strings for now, and convert them to numbers later
age = input("Please enter your age: ")
height = input("Please enter your height: ")
weight = input("Please enter your weight: ")

There’s a lot of repetition in this snippet of code. Each line is exactly the same except for the name of the variable and the name of the property we ask for (and these values match each other, so there’s really only one difference). When we write code like this we’re likely to do a lot of copying and pasting, and it’s easy to make a mistake. If we ever want to change something, we’ll need to change each line.

How can we improve on this? We can separate the parts of these lines that differ from the parts that don’t, and use a loop to iterate over them. Instead of storing the user input in separate variables, we are going to use a dictionary – we can easily use the property names as keys, and it’s a sensible way to group these values:

person = {}

for prop in ["name", "surname", "age", "height", "weight"]:
    person[prop] = input("Please enter your %s: " % prop)

Now there is no unnecessary duplication. We can easily change the string that we use as a prompt, or add more code to execute for each property – we will only have to edit the code in one place, not in five places. To add another property, all we have to do is add another name to the list.

Exercise 7

  1. Modify the example above to include type conversion of the properties: age should be an integer, height and weight should be floats, and name and surname should be strings.

Answers to exercises

Answer to exercise 1

  1. Here is an example program:

    total = 0
    number = 0
    
    while total < 200:
        number += 1
        total += number**2
    
    print("Total: %d" % total)
    print("Last number: %d" % number)
    
  2. Here is an example program:

    GUESSES_ALLOWED = 10
    SECRET_WORD = "caribou"
    
    guesses_left = GUESSES_ALLOWED
    guessed_word = None
    
    while guessed_word != SECRET_WORD and guesses_left:
        guessed_word = input("Guess a word: ")
    
        if guessed_word == SECRET_WORD:
            print("You guessed! Congratulations!")
        else:
            guesses_left -= 1
            print("Incorrect! You have %d guesses left." % guesses_left)
    

Answer to exercise 2

  1. Here is an example program:

    total = 0
    
    for i in range(1, 10 + 1):
        total += i
    
    print(total)
    
  2. Remember that we can use the sum function to sum a sequence:

    print(sum(range(1, 10 + 1)))
    
  3. Here is an example program:

    num = int(input("Please enter an integer: "))
    
    num_fac = 1
    for i in range(1, num + 1):
        num_fac *= i
    
    print("%d! = %d" % (num, num_fac))
    
  4. Here is an example program:

    total = 0
    product = 1
    
    for i in range(1, 10 + 1):
        num = float(input("Please enter number %d: " % i))
        total += num
        product *= num
    
    average = total/10
    
    print("Sum: %g\nProduct: %g\nAverage: %g" % (total, product, average))
    
  5. Here is an example program:

    numbers = []
    
    for i in range(10):
        numbers[i] = float(input("Please enter number %d: " % (i + 1)))
    
    total = 0
    product = 1
    
    for num in numbers:
        total += num
        product *= num
    
    average = total/10
    
    print("Sum: %g\nProduct: %g\nAverage: %g" % (total, product, average))
    

Answer to exercise 3

  1. Here is an example program:

    calendar = []
    
    for m in range(12):
        month = []
    
        for w in range(4):
            month.append([])
    
        calendar.append(month)
    
  2. Here is an example program:

    (JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST,
    SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER) = range(12)
    
    (WEEK_1, WEEK_2, WEEK_3, WEEK_4) = range(4)
    
    calendar[JULY][WEEK_2].append("Go on holiday!")
    

Answer to exercise 4

  1. Here is an example program:

    months = ("January", "February", "March", "April", "May", "June",
              "July", "August", "September", "October",
              "November", "December")
    
    num_days = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    
    month_dict = {}
    
    for month, days in zip(months, days):
        month_dict[month] = days
    
  2. Here is an example program:

    months = ("January", "February", "March", "April", "May", "June",
              "July", "August", "September", "October",
              "November", "December")
    
    num_days = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
    
    # the zipped output is a sequence of two-element tuples,
    # so we can just use a dict conversion.
    month_dict = dict(zip(months, days))
    

Answer to exercise 5

  1. Here is an example program:

    number_string = ", ".join(str(n) for n in range(1, 11))
    print(number_string)
    
  2. Here is an example program:

    calendar = [[[] for w in range(4)] for m in range(12)]
    
    (JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST,
    SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER) = range(12)
    
    (WEEK_1, WEEK_2, WEEK_3, WEEK_4) = range(4)
    
    calendar[JULY][WEEK_2].append("Go on holiday!")
    
  3. calendar = [[] for w in range(4) for m in range(12)]
    

Answer to exercise 6

  1. Here is an example program:

    while (True):
        num = int(input("Enter an integer: "))
        if num == 99:
            break
        if num % 2:
            continue
        print num
    
  2. Here is an example program:

    print("Please enter positive integers to be averaged. Enter a negative integer to terminate the list.")
    
    nums = []
    
    while True:
        num = int(input("Enter a number: "))
    
        if num < 0:
            break
    
        nums.append(num)
    
    average = float(sum(nums))/len(nums)
    print("average = %g" % average)
    
  3. Here is an example program:

    menu = """-- Calculator Menu --
    0. Quit
    1. Add two numbers
    2. Subtract two numbers
    3. Multiply two numbers
    4. Divide two numbers"""
    
    selection = None
    
    while selection != 0:
        print(menu)
        selection = int(input("Select an option: "))
    
        if selection not in range(5):
            print("Invalid option: %d" % selection)
            continue
    
        if selection == 0:
            continue
    
        a = float(input("Please enter the first number: "))
        b = float(input("Please enter the second number: "))
    
        if selection == 1:
            result = a + b
        elif selection == 2:
            result = a - b
        elif selection == 3:
            result = a * b
        elif selection == 4:
            result = a / b
    
        print("The result is %g." % result)
    

Answer to exercise 7

  1. Here is an example program:

    person = {}
    
    properties = [
        ("name", str),
        ("surname", str),
        ("age", int),
        ("height", float),
        ("weight", float),
    ]
    
    for prop, p_type in properties:
        person[prop] = p_type(input("Please enter your %s: " % prop))