Repeat

Computers are good at doing the same thing many times without getting bored or making a slip. This module shows how to say "do this again" once, and let Python do the repeating.

Before this, you can: update a variable with x = x + 1; say which indented lines belong to an if; use a variable inside a call's arguments.

By the end you will be able to read a loop and say how many times it runs and what its variable holds each time, write a loop that places shapes, and add up as you go.

The same line, five times

Five circles in a row:

from scimigo import canvas, circle

canvas(600, 400)
circle(100, 200, 20, color="orange")
circle(200, 200, 20, color="orange")
circle(300, 200, 20, color="orange")
circle(400, 200, 20, color="orange")
circle(500, 200, 20, color="orange")

This works. It also takes five lines to say one thing: fifty circles would need fifty lines, and changing the size would mean editing every one. The five lines are almost the same; only one number changes, and it changes by the same amount each time. That is the situation a loop is for.

for and range

Start with a loop that draws nothing:

for i in range(3):
    print("hop")
hop
hop
hop

Read the first line as: do the indented lines 3 times. Its parts, in order: the word for, a name (here i), the word in, range(3), and a colon. Under it, indented by four spaces, are the lines to repeat. This is the same rule you met with if: indentation says which lines belong.

Each time through the indented lines is called a turn of the loop.

The loop variable counts for you

The name after for is a variable, and Python gives it a new value on every turn:

for i in range(4):
    print(i)
0
1
2
3

Two things here surprise almost everyone. The counting starts at 0, not 1. And range(4) never reaches 4: it gives four values, 0, 1, 2 and 3, and then the loop is over.

turn i
1st 0
2nd 1
3rd 2
4th 3

So range(4) means four turns, and on the last one i is 3. You can call the variable anything; i is a habit, and a longer name is often clearer.

What is inside the loop?

Only the indented lines repeat. The first line after them that is not indented runs once, when the loop has finished:

for i in range(3):
    print("hop")
print("done")
hop
hop
hop
done

Indent that last line and it becomes part of the loop, and the program says something different:

for i in range(3):
    print("hop")
    print("done")
hop
done
hop
done
hop
done

The two programs differ by four spaces. When a loop does too much or too little, look at the indentation before anything else.

Using i to place things

A loop that printed the same word each time did not need i. A loop that draws does, because each shape belongs somewhere different. The trick is to work the position out from i:

for i in range(5):
    x = 100 + i * 100
    print(i, x)
0 100
1 200
2 300
3 400
4 500

On the first turn i is 0, so x is 100 + 0, which is 100. Each turn after that, i is one bigger and x is 100 bigger. Those are the five x positions from the top of this lesson. Now the row of circles is three lines, however many circles there are:

from scimigo import canvas, circle

canvas(600, 400)
for i in range(5):
    x = 100 + i * 100
    circle(x, 200, 20, color="orange")

In 100 + i * 100, the first 100 is where the row starts and the second is the gap between one circle and the next. To pack them closer, change the gap. To draw more, change the number in range.

Counting from somewhere else

range can be told where to start, and how big a step to take:

for n in range(2, 6):
    print(n)
2
3
4
5

With two arguments, range(start, stop) begins at start and stops before stop. With three, the last is the step:

for x in range(100, 600, 100):
    print(x)
100
200
300
400
500

Here the loop variable is the position itself, so no arithmetic is needed. The stop is 600 and the last value is 500: whatever the step, range gives the values that come before the stop and never the stop itself.

Counting with i and working out x, or letting range produce x directly, are two ways to write the same loop. Use whichever you find easier to read.

Adding up as you go

A loop can build up an answer over its turns. Put a variable before the loop, and update it inside:

total = 0
for i in range(1, 5):
    total = total + i
print(total)
10

total = total + i is the three moves from the last module, done once per turn: read total, add this turn's i, store the result back.

turn i total after the turn
1st 1 1
2nd 2 3
3rd 3 6
4th 4 10

total = 0 has to come before the loop. Inside it, the total would be set back to nothing at the start of every turn. And print(total) is not indented, so it runs once at the end. Indented, it would print the total after every turn, which is sometimes exactly what you want.

You will often see total = total + i written as total += i. It means the same thing.

In the lab

You will say how many times a loop runs and what its variable holds before you run it, turn five circles into eight, draw a staircase where every stair is worked out from the loop variable, and chart twelve weeks of savings.