SchoolWhool
Quizzes and saved progress, freeSign in freeSign in

Python 2.3Free video19 minLesson 3 of 4 in Module 2

for Loops and range

Iterate over any sequence.

Free sample. Everything in this module opens with a free account.

Watch or read the lesson: for Loops and range

01A week of step counts: one item at a time

In the previous lesson, you learned how to repeat a block of code with a while loop. Python keeps running that block for as long as a condition stays True. But there is another situation where you often need repetition.

Imagine you have been tracking how many steps you walk each day. Here are your step counts for one week:

week = [8200, 10450, 6300, 12000, 9100, 7400, 11050]
len(week)
7

That is seven numbers, one for each day. You want to print each day's count, and then calculate the total for the week.

You could write a separate print statement for each day. But what if you had a whole year's worth of counts? Instead, you want Python to go through the values one at a time and repeat the same operation on each of them. That is exactly what a for loop is designed to do.

A list

Notice how the counts are stored: inside square brackets, separated by commas. This is called a listKey termValues in square brackets, in order, separated by commas: [8200, 10450, 6300]. Module 2 uses lists only in loops; Python 3.1 teaches them.. A list lets you store multiple values together, in a particular order. You will explore lists in much more detail in the next module. For now, all you need to know is that week holds seven values together, and you want to go through them one by one.

02The for loop: the loop variable, and what it can loop over

So how do you do that? Here is your first for loop. It starts with for steps in week:, and underneath it, indented, is a print statement that displays steps:

for steps in week:
    print(steps)
8200
10450
6300
12000
9100
7400
11050

Here is what is happening. The word for tells Python that you want to iterate over something, that is, to go through it item by item. In this case, that something is the list called week. The name steps is called the loop variableKey termThe name a for loop binds to each item in turn: steps in for steps in week:. After the loop it retains the last value assigned to it; an empty loop does not bind it.: it is the name that receives each item as the loop progresses.

When the cell runs, Python first takes the first value from the list, 8200, and binds the name steps to it. Then it executes the indented block, which prints 8200.

Now, instead of checking a condition the way a while loop does, Python automatically moves on to the next item. So steps now refers to 10450, and the same print statement runs again. Then Python moves to 6300, then 12000, and it continues until it reaches the last value, 11050. Once there are no more items, the loop finishes.

Iterables

That is the key difference between the two loops:

  • A while loop repeats a block as long as a condition is True.
  • A for loop goes through the items of an iterable, one at a time.

IterableKey termAnything a for loop can go through, one item at a time: a list, a string, a range. is a new term. An iterable is something Python can get items from, one after another. Lists are iterable. Strings are iterable too. And you will see several other examples in this lesson.

The word in

You might have noticed the word in again. You met in in the operators lesson, where it checked membership, for example whether a character exists inside a string. In a for statement it has a different role. It is part of the loop syntax, and it tells Python which iterable to get the items from.

03Accumulators and direct iteration versus an index

Printing each day's steps is useful. But what if you want to know how many steps you walked during the entire week? You can use the same loop to calculate that.

First, create a variable called total and initialize it to zero. Then, inside the loop, instead of printing each value, add it to total. You can use the augmented assignment operator, total += steps. Remember, that is just a shorter way of writing total = total + steps.

total = 0
for steps in week:
    total += steps
print(total)
64500

The running total

Here is what happens, step by step. Before the loop starts, total is 0.

  • On the first iteration, steps is 8200. Python adds 8200 to total, and total becomes 8200.
  • On the second iteration, steps is 10450. Python adds that too, and total becomes 18650.
  • Then comes the third day, with 6300 steps, and total increases to 24950.

The same thing happens for every remaining day. Once all seven values have been processed, total is 64500. So you walked 64,500 steps that week.

There is a name for this pattern. It is called an accumulatorKey termA name that collects a result across a loop's iterations. It is created before the loop (total = 0), updated in the body (total += steps), and read after it.: a variable that builds up a result across multiple iterations. Here, total is accumulating the sum of the step counts. This is a pattern you will use all the time. Whenever you need to calculate a sum, count certain items, or build a result gradually, you will often use an accumulator.

Initialize the accumulator once

Predict first

Notice where total was set to zero: before the loop, not inside it. What would happen if you put total = 0 inside the loop body instead? Think it through before reading on.

I have a guess. Show meHide the answer

Every time Python starts a new iteration, it would reset total back to zero. You would lose everything you had added in the previous iterations, so instead of the sum of all seven days, you would keep starting over. That is not what you want.

So an accumulator follows three steps:

  1. Initialize it once, before the loop.
  2. Update it during every iteration.
  3. Read the result after the loop finishes.

The same total with a while loop

Could you have done this with a while loop? Absolutely. First, reset total to zero, so you do not add the week's steps on top of the total you already calculated.

This time you need to keep track of which position you are currently looking at. So create a variable called i and initialize it to zero. A variable like this is commonly used as an index: a number that represents the position of an item in a sequence. In Python, indexing starts at zero. The first item is at index 0, the second is at index 1, and so on.

You want to keep going as long as the index is smaller than the number of items in the list. For that, you can use the len() function: len(week) tells you how many items are in the list, which here is seven. So the condition becomes i < len(week).

Inside the loop, you access the item at position i by writing week[i], add it to total, and then increase i by one:

total = 0
i = 0
while i < len(week):
    total += week[i]
    i += 1
print(total)
64500

You get the same result, 64,500.

Direct iteration

Both approaches work. But notice how much you had to do with the while loop. You had to:

  • create an index,
  • check whether it was still within the valid range,
  • use it to access each item,
  • and remember to increase it after every iteration.

With a for loop, Python gets each item from the iterable for you, so you do not need that index. You simply say: go through each value in week. That is why, when you want to process every item in a sequence, a for loop is usually the more natural choice.

04Iterating over a string

You can loop over a string as well. Suppose you want to count the vowels in the word "education". How would you do it?

A string is iterable, which means a for loop can go through its characters one at a time. Start with a variable called vowels, initialized to zero. Then write a for loop over the characters in "education". On each iteration, the loop variable receives the next character: first e, then d, then u, and so on.

Inside the loop, you want to check whether the current character is a vowel. For that, you can use the membership operator in: check whether the letter appears in the string "aeiou", and if it does, increase the vowel counter.

vowels = 0
for letter in "education":
    if letter in "aeiou":
        vowels += 1
print(vowels)
5

Python finds e, which is a vowel. Then u, another vowel. Then a, i and o. So the final count is 5.

Notice that this cell uses in twice, in its two roles. In for letter in "education", it is part of the loop syntax. In letter in "aeiou", it is the membership operator. And once again, you have used a loop and an accumulator. The only difference is that this time you are iterating over a string instead of a list.

05range: a sequence of whole numbers

Here is another situation. What if you do not have a list or a string to iterate over? What if you simply want to repeat something a certain number of times, say five times?

Predict first

Python gives you a built-in type called rangeKey termA sequence of whole numbers from a start, up to but not including a stop, with an optional step: range(0, 20, 5) gives 0, 5, 10, 15. It works each number out when the loop asks for it., and it is extremely useful with for loops. Suppose you write for i in range(5): and print i inside the loop. What do you think Python displays? Think it through before reading on.

I have a guess. Show meHide the answer
for i in range(5):
    print(i)
0
1
2
3
4

That is five numbers. But notice that they started at zero and stopped before five. That is how range works by default: when you give it just one argument, it starts at zero and generates values up to, but not including, the stop value. So range(5) gives you five values, from 0 to 4.

A start value

Predict first

What if you do not want to start at zero? You can provide a starting value too, for example range(1, 10). What is the last number this range produces: 9, or 10? Think it through before reading on.

I have a guess. Show meHide the answer
for i in range(1, 10):
    print(i)
1
2
3
4
5
6
7
8
9

It is 9, because the start value is included but the stop value is excluded. So range(1, 10) gives you the numbers 1 through 9. If you want the numbers 1 through 10, use range(1, 11):

for i in range(1, 11):
    print(i)
1
2
3
4
5
6
7
8
9
10

A step

Predict first

There is also a third argument you can provide, called the step. The step determines how much the value changes between iterations. Suppose you write range(0, 20, 5). What numbers do you think you will get? Work through the values one at a time, then think it through before reading on.

I have a guess. Show meHide the answer
for i in range(0, 20, 5):
    print(i)
0
5
10
15

You get 0, 5, 10 and 15. The next value would be 20, but remember, the stop value is not included. So the range ends at 15.

Counting backwards

What if you want to count backwards? You can use a negative step. Here is range(10, 0, -3): a range from 10 to 0, with a step of minus three.

for i in range(10, 0, -3):
    print(i)
10
7
4
1

It starts at 10 and subtracts 3 each time, so you get 10, 7, 4 and 1. The next value would be -2, which has already passed the stopping boundary, so the range ends.

When a range is empty

Predict first

The direction of the step matters. Suppose you write range(5, 1). What happens now? Think it through before reading on.

I have a guess. Show meHide the answer
for i in range(5, 1):
    print(i)

This cell prints nothing at all. The default step is positive one, so the range starts at 5 and tries to move toward 1, and increasing the value will never get it there. So this range produces no values, and the loop body does not run at all.

06enumerate and zip

You can also use a loop to print a restaurant receipt. Suppose you have a list of items, "Pasta", "Salad" and "Soup", and you want to print them as a numbered list, like this:

1. Pasta
2. Salad
3. Soup

One way to do this is to use range with the length of the list. You loop over the indices, and then use each index to access the corresponding item. Since the indices start at zero, you add one when displaying the number:

items = ["Pasta", "Salad", "Soup"]
for i in range(len(items)):
    print(f"{i + 1}. {items[i]}")
1. Pasta
2. Salad
3. Soup

That works.

enumerate

But Python gives you a more convenient option, called enumerate(). The enumerate function lets you iterate over a sequence while keeping track of a counter. So instead of managing the index yourself, you can write:

for number, item in enumerate(items, start=1):
    print(f"{number}. {item}")
1. Pasta
2. Salad
3. Soup

Here is what is happening. On each iteration, enumerate gives you two values: a number, and the corresponding item. You assign those two values to two names, number and item. This is the same kind of multiple assignment you learned earlier, where one line binds several names at once.

Because you passed start=1, the numbering begins at one instead of zero. So on the first iteration, number is 1 and item is "Pasta". On the second iteration, number is 2 and item is "Salad", and so on. The f-string prints them together, and you get your numbered list.

zip

A receipt needs more than item names. It also needs prices, so here is another list with the prices of the three items: 12.50 for Pasta, 8.25 for Salad and 6.00 for Soup.

Notice that the two lists are related by position. The first item goes with the first price, the second item with the second price, and so on. So how do you iterate over both lists together?

Python has another useful built-in function for this, called zip(). The zip function combines items from multiple iterables, one position at a time. You write it like this:

prices = [12.50, 8.25, 6.00]
for item, price in zip(items, prices):
    print(item, price)
Pasta 12.5
Salad 8.25
Soup 6.0

On the first iteration, you get "Pasta" and 12.5. On the second, "Salad" and 8.25. And on the third, "Soup" and 6.0. So both the item name and its price are available inside the loop.

Here is something important. zip does not actually know which price belongs to which item. It simply pairs values based on their positions. So it is your responsibility to make sure the two lists are in the correct order.

The receipt

Now you can build the full receipt. Inside the loop, print each item and its price with an f-string, using the format specifiers you learned earlier:

  • For the item name, :<10 means left alignment with a minimum width of ten characters.
  • For the price, :>8.2f means right alignment with a minimum width of eight characters, and two decimal places.

That way, all the item names line up on the left, and all the prices line up neatly on the right.

You also want the total, so before the loop, initialize total to zero, and inside the loop, add each price to it:

items = ["Pasta", "Salad", "Soup"]
prices = [12.50, 8.25, 6.00]
total = 0.0
for item, price in zip(items, prices):
    print(f"{item:<10}{price:>8.2f}")
    total += price
print(f"{'Total':<10}{total:>8.2f}")
Pasta        12.50
Salad         8.25
Soup          6.00
Total        26.75

First, Pasta is printed with its price of 12.50, and total becomes 12.50. Then Salad is printed with its price, and total becomes 20.75. Finally, Soup is printed with its price of 6.00, and total becomes 26.75. After the loop finishes, the last line prints the total.

And there you have it: a simple receipt generated with a for loop. One iteration for each item, one formatted line for each item, and one addition to the running total.

07Nested loops

There is one more important pattern to explore: nested loops. Earlier in this module, you put an if statement inside another if statement. You can do the same thing with loops, and put a for loop inside another for loop. This becomes useful when you are working with rows and columns.

Take a simple multiplication table, with three rows and three columns. The table looks like this:

  1  2  3
  2  4  6
  3  6  9

How do you generate that with loops? Think about the structure. There are three rows, and for every row, you need to calculate three values. So you can use one loop for the rows, and another loop for the columns.

Start with the outer loop. It uses range to generate the row numbers from 1 to 3. Inside that loop, create an empty string called line, which will hold the values for the current row. Then add another for loop inside it. This inner loop goes through the column numbers, also from 1 to 3. For every combination of row and column, calculate their product, and append it to line with an f-string. The format specifier :3 gives each number a width of three characters, so the columns line up.

for row in range(1, 4):
    line = ""
    for col in range(1, 4):
        line += f"{row * col:3}"
    print(line)
  1  2  3
  2  4  6
  3  6  9

The inner loop runs in full

Here is what happens. The outer loop starts with row equal to 1. Python creates an empty line, and then the inner loop begins:

  • First, col is 1, so row * col gives 1, which is added to line.
  • Then col becomes 2, so the product is 2, and that is added too.
  • Then col becomes 3, and the product is 3.

Now the inner loop has finished, so Python prints the completed line. That is the first row.

Then the outer loop moves to row 2. Python creates a new empty line, and the inner loop starts again from the beginning. This time the products are 2, 4 and 6, and that is the second row. Then the outer loop moves to row 3, and the inner loop gives 3, 6 and 9: the third row. Now the table is complete.

Notice that the inner loop runs three times for every single iteration of the outer loop. Since the outer loop runs three times, the inner loop body executes nine times in total.

That is the basic idea behind nested loops. One loop controls the larger structure, and another loop handles the repeated work inside each part of that structure. You will see this pattern again when you work with tables, matrices and multidimensional arrays.

08Recap and challenge: for, iterables, range, enumerate and zip

A for loop lets you iterate over items without managing a stopping condition yourself. You started with a list of daily step counts, used a loop to print each value, and then used an accumulator to add them up to 64,500, without the index a while loop needs. You also saw that strings are iterable, and used a loop to count the vowels in "education".

Then you explored range(), which is useful when you want to repeat something a particular number of times, or work with a sequence of integers. Its start is included, its stop is excluded, and its step can be negative. You learned how enumerate() gives you a counter alongside each item, and how zip() lets you iterate over several sequences together, paired by position. Finally, you used nested loops to generate a small multiplication table.

Your challenge

Create a daily step report, using the same seven step counts from the beginning of this lesson:

week = [8200, 10450, 6300, 12000, 9100, 7400, 11050]
  1. Print one line for each day, starting with Day 1, followed by that day's step count.
  2. Format each number with comma separators, so 8200 appears as 8,200.
  3. Add a mark next to every day where the step count is at least 10,000.

You can use enumerate() to generate the day numbers, and an if statement to identify the active days. Try to build it yourself before looking back at the examples.

The next lesson explores two more useful tools for controlling loops.