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.
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.
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 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.
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.
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.
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.
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.
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.