In addition to the while loop, Python also provides the for
loop. Its syntax has the form:
for [variable] in [collection of values]: do something for each member of the collection do more... else: do something after all values in the collection have been processed
The [variable] is applied successively to each datum in the [collection of values] and the code in the first block is run in each case. After all the data in the collection have been processed, control passes to the else
block (if present; it’s optional). Note that ‘in’ is a keyword in Python, and cannot be used as a variable name.
This is a rare instance in which a variable does not need to be initialized before it is used. The [variable] in the for statement is initialized by setting it to the first datum in the [collection of values].
Like the while loop, a for loop can be terminated at any point by using the break
statement. Also as with the while loop, a continue
statement causes the remainder of the current iteration to be skipped, with control passing back to the top line of the loop, where the next element of the collection is then processed.
The [collection of values] can be any of Python’s collective data types, including lists, tuples, sets and dictionaries. We’ll examine these data types later, although their use with for loops is straightforward: the loop just processes each element in the data type, as you’d expect.
The range() function
To illustrate for loops, we’ll use the range()
function, as this gives a behaviour closest to what programmers in languages such as C++, C# and Java are used to. It has the syntax:
# Integers from 0 to stop - 1 range(stop) # Integers from start to stop - 1 range(start, stop) # Integers from start to stop - 1 in intervals of step range(start, stop, step)
The first form generates an iterable object containing integers from 0 up to stop - 1
, in intervals of 1. The second form does the same, but starts at ‘start’ rather than 0. The last form generates integers from start
to stop - 1
with an interval of step
between each pair of integers. The first two forms are just shorthand for the third, so we have range(stop)
== range(0, stop)
== range(0, stop, 1)
and range(start, stop)
== range(start, stop, 1)
.
range()
generates an object which can be accessed like an array of integers, so we can specify an index to access a particular element. For example, enter the following in the console:
ran = range(3, 20, 2) ran[3]
The range array consists of the numbers [3, 5, 7, 9, 11, 13, 15, 17, 19], so ran[3]
has the value 9. The sequence always ends with the largest number that is strictly less than stop.
range()
can also generate values in decreasing order if the step is a negative integer. In this case, start must be greater than stop, otherwise range()
will give an empty array. Thus range(10, 2, -1)
gives the array [10, 9, 8, 7, 6, 5, 4, 3]. In the decreasing sequence case, the sequence ends with the smallest number that is strictly greater than stop.
If you want to see the complete array generated by range()
, you need to convert it to a list. For example, typing
range(3, 20, 2)
into the console just produces range(3, 20, 2)
as output. However, if you try this:
ranlist = list(range(3, 20, 2)) ranlist
you’ll get the list [3, 5, 7, 9, 11, 13, 15, 17, 19] printed out.
Using range() with for loops
The range()
function can be used to provide the [collection of values] in the for loop syntax above. There is no need to convert range()
to a list in order to use it in a for loop; the for loop is intelligent enough to iterate through the values in the range()
object on its own.
Here’s an example that prints out a list of cubes for integers in a given range, and also illustrates another use of a for loop:
print('Cube table') limits = input('Enter start, stop, step: ') bounds = [int(i) for i in limits.split()] for num in range(bounds[0], bounds[1] + 1, bounds[2]): print(str(num) + ' ** 3 = ' + str(num **3)) else: print('List finished.')
Line 2 reads in start, stop and step as a single string, so we need to split this string into 3 separate values and convert them to ints. There are several ways this can be done, but probably the most concise is that shown in the example, although it uses a technique called list comprehension which we will cover in more detail when we examine lists. Basically, line 3 first uses the split()
function in the string library to split the limits
string. By default, split()
splits a string at each occurrence of whitespace and returns a list of the separate pieces. These pieces are still strings, so we need to convert them to ints before they can be used in the range()
function. The statement on line 3 uses a for loop to iterate over the elements in the split list and applies int(i)
to each such element. By enclosing the statement in square brackets, the result of this operation is returned as a list, which is referenced by the variable bounds.
Once the bounds list has been constructed, we use it in line 4 to provide the arguments for the range()
function and calculate the table of cubes. When the loop finishes, control passes to the else block for the final message.
Exercise
Modify the cubes program above as follows:
(a) The user may input 1, 2 or 3 values rather than always 3. If the user enters a single number, print out a table of cubes for numbers from 1 up to that number, in steps of 1. If the user enters 2 numbers, calculate the table of cubes from the first number up to (and including) the second, in steps of 1. If the user enters 3 positive numbers, the program should function as before.
(b) The program should generate a table in descending order if the step variable is negative. This should occur only if the user enters 3 numbers with the last one being negative.
(c) Replace the list comprehension (line 4 above) with an ordinary for loop that converts the numbers entered by the user from strings to ints.
(d) The program should loop continuously allowing the user to generate as many tables as desired. Entering ‘quit’ should terminate the program.
(e) Check that step is not zero, since passing a zero step size into range()
causes an error. If step is zero, skip the rest of that iteration and ask the user to try again.
print('Cube table') while True: limits = input('Enter 1, 2 or 3 ints (\'quit\' to exit): ') if limits == 'quit': break limits = limits.split() # Split into separate strings numLimits = len(limits) # Find the number of ints entered for i in range(numLimits): # Convert strings to ints limits[i] = int(limits[i]) bounds = [1, 1, 1] # Initialize the bounds list if numLimits == 1: # Determine start, stop and step bounds[1] = limits[0] elif numLimits == 2: bounds[0] = limits[0] bounds[1] = limits[1] else: bounds[0] = limits[0] bounds[1] = limits[1] bounds[2] = limits[2] if bounds[2] == 0: # If step is 0, skip this iteration continue if bounds[2] < 0: # Adjust stop so that a full list is printed stop = bounds[1] - 1 else: stop = bounds[1] + 1 for num in range(bounds[0], stop, bounds[2]): print(str(num) + ' ** 3 = ' + str(num **3)) else: print('List finished.')
Most of the code should be self-explanatory with the comments, but here’s a summary.
The while loop on line 2 allows the user to enter as many data sets as desired. If ‘quit’ is input, line 5 breaks out of the while loop and ends the program. Line 6 splits the input into separate strings and line 7 determines how many numbers the user entered. Lines 9 and 10 convert these into ints.
Lines 14 through 22 sort out the values of start, stop and step that will be used in the call to range()
in line 31. If the user entered only 1 number, then the table should go from 1 to that number, in increments of 1, so only the value of stop (bounds[1]
) needs to be set. If 2 numbers were entered, the first is start (bounds[0]
) and the second is stop (bounds[1]
), while if 3 numbers were entered, we set the values of start, stop and step.
Line 23 checks that the step size is non-zero, and line 24 skips the rest of the iteration if it is.
Lines 26 through 29 adjust the value of stop to take account of the fact that the second argument in range()
is non-inclusive, so we need to subtract 1 if we want a descending sequence or add 1 if we want an ascending sequence. Finally, lines 31 and 32 print out the table as before.