Lists and looping

What’s a list?

So far, we have discussed three of Python’s data types: integers (int), floating-point numbers (float), and strings (str). Python also includes a type called a list which is, appropriately, a list of other values. Lists are created by writing a comma-separated sequence of elements in square brackets. Each of these elements is simply the Python code for another value, like so:

[1, 3, 5, 7]

The above is a list of the first four odd natural numbers. Elements of a list may be any legal Python expression. For instance, all of the following are lists:

[1+2, 3+4, 5+6]      # equivalent to the list [3,7,11]
[1.0, 3.5, 2.0]      # floats may be members of lists
["Ann", "Bjorn"]    # so can strings
[[1, 3, 5], [2, 4, 6]]  # this is a list of lists!

We discuss lists in greater detail later. For now, lists are most interesting because we can “loop over them.” That leads us to our next question...

What’s a loop?

The code examples presented so far consist of a series of statements which are executed in order. For instance, consider the following source:

print("How are you today?")
mood = input()
print("Me too!")

When executed, this program will print a prompt (How are you today?), wait for the user to answer the question, and then print a follow-up message. These statements occur in the order they occur in the source code and each of them will only run once. In a sense, the code runs in a straight line from the top of the file to the bottom.

By contrast, a loop is a piece of code which may execute many times (or perhaps even not at all). One such loop is the for loop, an example of which appears in the following code:

for name in ["Alice", "Bjorn", "Cayman", "Duanphen", "Esfir", "Farah"]:
    print("I know " + name + ".")
    print("%s is a friend of mine." % (name))
print("Those are the people I know.")

In the above code, for and in are keywords in the Python language. Between them, name describes the name of a variable. After in, a list must appear, followed by a colon (:). Finally, note that two print statements beneath the for loop are indented, forming what is known as the body of the loop.

When the for loop is executed, Python will run the entire body of the loop once for each element in the for loop’s list. Each time the body runs, the variable (here, name) will be set to that element. So the steps of the above program are:

  1. Set name to "Alice".
  2. Execute both of the statements in the body of the loop.
  3. Set name to "Bjorn".
  4. Execute both of the statements in the body of the loop again.
  5. Continue the above process until we have set name to "Farah" and run the body of the loop.
  6. Having completed the for loop, now execute the final print statement.

The output of the program is therefore:

I know Alice.
Alice is a friend of mine.
I know Bjorn.
Bjorn is a friend of mine.
I know Cayman.
Cayman is a friend of mine.
I know Duanphen.
Duanphen is a friend of mine.
I know Esfir.
Esfir is a friend of mine.
I know Farah.
Farah is a friend of mine.
Those are the people I know.

Of course, we can achieve the above output using straight-line code as well, but it is far more tedious!

range

In the above example, the for loop keeps the code small but doesn’t let us do anything we couldn’t do without it. for loops become more interesting if we give them lists created using the range function.

The range function is built into Python and returns an object of type range that we can iterate over. For example, if we want to loop over the numbers 0,1,2,...,99, we do not want to have to write out each number in a list beginning [0,1,2,3,4,5,...]. Instead, range gives us the ability to create lists of integers that start and stop at any numbers we choose. For now we will give range two arguments: a start value which will be included in the output, and a stop value which will not be included in the output. An example of using range is shown below:

>>> range(0,10)         # start at 0 (inclusive), end at 10 (exclusive)
range(0, 10)
>>> type(range(0,10))
<class 'range'>

In its current form, this output is not very helpful for understanding our code. For now, we will always convert the output of range to a list using type conversion as shown below:

>>> list(range(0,10))           # convert to a list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(2,8))            # includes 2, excludes 8
[2, 3, 4, 5, 6, 7]

Now we can use range to loop over very large lists:

for number in list(range(0,1000)):
    print(number)

These two lines execute the print statement a total of 1000 times!

The range function can take any int values, even ones from user input. If we want to give the user control of how many times we run our loop’s body, for instance, we might write a program like this:

total_str = input("How many numbers should I print? ")
total = int(total_str)
for number in list(range(0,total)):
    print(number)

Now, the number of times the print statement runs is up to the user. We could further modify this code to let the user choose the start and stop values of the loop. Since for loops are able to iterate over the values in range automatically, we can omit the conversion to a list as shown below:

start_str = input("Which number should I print first? ")
start = int(start_str)
stop_str = input("Which number should make the loop stop? ")
stop = int(stop_str)
for number in range(start,stop):
    print(number)

Now the loop will start at the first number the user chooses, and stop right before the second number the user chooses. It is important to note that the difference between stop and start is the number of times the loop is executed. If the user chose 47 for the start and 63 for the end, the loop would be executed 63-47=16 times.

If range is used with only one argument, i.e. range(5), it will by default have a start value of 0. In addition, if range is used with three arguments, i.e. range(0,20,2) the third argument is interpreted as the step size, meaning it will start at 0, then step 2 so the next number is 2, then 4,6,8, etc.

>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(0,20,2))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Accumulators

One helpful technique to use with loops is to create a variable called an accumulator. An accumulator variable is like any other variable, but it is used to gather up (accumulate) information as we run the loop.

Consider a program that adds up all of the numbers from 0 to some number given by the user. That is, if the user provides 8, it will produce 36 (which is the result of computing 0+1+2+3+4+5+6+7+8). How would we write such a program? We can’t loop to create more + operations; our loop can only run a fixed list of statements over and over again.

This problem is best solved by an accumulator which will track the total we have added so far in the program. At the beginning of the program, we set the accumulator to 0 (because we haven’t done any addition yet). Then, the loop body adds another number to the accumulator each time it runs.

last_number_str = input("Sum up to what number? ")
last_number = int(last_number_str)
sum = 0  # this is our accumulator
for number in list(range(0, last_number+1)):  # +1 to include last_number itself
    sum = sum + number  # increases the sum variable by number
print("The sum of those numbers is: %d" % (sum))

We set the sum accumulator to 0 above because 0 is the unit of addition: it is the value which has no effect when it is added to another number. To compute the factorial of a number (rather than the summation), our loop would need to multiply the accumulator and so its initial value would be 1 (the unit of multiplication).

Glossary

body
The part of a loop statement which may run many times (or not at all).
element
A value which appears in a list.
list
A type of value which contains other values, called elements, in some order.
loop
Code which may execute many times (or not at all).

Exercises

  1. One example from this chapter prints all of the numbers from 0 to a number that the user provides. Write a program that prints all of the odd numbers from 0 to a number that the user provides.

  2. What is the output of the following for loops?

    for i in range(0):
        print("hello")
    
    for i in []:
        print("goodbye")
    
  3. Some of the above loops use lists directly (e.g. [1, 2, 3]) or use the range function. Do the following work?

    x = range(5)
    for i in x:
        print("hello")
    
    x = 5
    for i in x:
        print("hello")
    
  4. Technically, for loops work with any sequence in python. A string is a sequence. What is the output of the following loop?

    mystr = "Swarthmore"
    for i in mystr:
      print(i)
      print("--------------")