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: Show
A petrol attendant performs the following actions when serving a customer:
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 In an event-controlled
loop, the computer stops the loop execution when a condition is no longer true. In Python, you can use the 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:
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
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 It is very important that you increment 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 # 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¶
The for statement¶Python’s other loop statement is the 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 i in range(1, 9): print(i) As we saw in the previous chapter, You can use pets = ["cat", "dog", "budgie"] for pet in pets: print(pet) At each iteration of the loop, the next element of the list 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 i, pet in enumerate(pets): pets[i] = pet.upper() # rewrite the list in all caps Like Why couldn’t we just write This brings us to a common 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¶
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 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¶
Iterables, iterators and generators¶In Python, any type which can be iterated over with a 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 # 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:
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 # 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 There is also a built-in function called 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¶
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 You can think of the comprehension as a compact form of
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_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¶
The break and continue statements¶
|