for loops and range — running a known number of times
When you know how many times, a for loop is the right choice. The three forms of range, why the end is excluded, and how to choose between for and while.
- 1Encounter
- 2Understand
- 3Worked
- 4Predict
- 5Apply
- 6Stretch
The problem we are solving
In the last mission, summing 1 to 5 took four lines, two of which existed only to keep count — a starting value and an increment. Forget the increment and you have an infinite loop.
But notice something about that kind of work: we knew in advance how many times it would run. Five. When that is the case there is no reason to shoulder the bookkeeping yourself — you can hand it to Python.
That is exactly what a for loop does. And because the counting is out of your hands, a for loop can never be infinite — which is its single biggest advantage.
By the end of this mission you can
- Run code a known number of times with a
forloop - Use all three forms of
range() - Explain why
range(1, 5)produces four numbers, not five - Loop over the characters of a piece of text
- Decide which of
forandwhilea given job wants
Prerequisites: while loops — running while a condition holds.
The simplest form
for number in range(5):
print(number)0
1
2
3
4Three lines of work in one, with no counter to manage. Read it as: "for each of the numbers `range(5)` produces, run the block once — and each time, put that number in `number`."
Two things stand out immediately:
It starts at zero, and 5 never appears — five numbers in total, but 0 through 4. This is the same rule Python applies everywhere: as the end index is excluded in a slice, so it is in a range.
The name number is your choice. for i in range(5) is equally fine, and i is the conventional name for a counter. But when the number means something, name it for the meaning — for student_number in range(30) reads by itself.
The three forms of range()
print("--- range(5) ---")
for i in range(5):
print(i, end=" ")
print()
print("--- range(2, 6) ---")
for i in range(2, 6):
print(i, end=" ")
print()
print("--- range(0, 10, 3) ---")
for i in range(0, 10, 3):
print(i, end=" ")
print()
print("--- range(5, 0, -1) ---")
for i in range(5, 0, -1):
print(i, end=" ")
print()--- range(5) ---
0 1 2 3 4
--- range(2, 6) ---
2 3 4 5
--- range(0, 10, 3) ---
0 3 6 9
--- range(5, 0, -1) ---
5 4 3 2 1The rules:
range(stop)— starts at0, ends beforestoprange(start, stop)— starts atstart, ends beforestoprange(start, stop, step)— advances bystepeach time; a negativestepcounts backwards
Check the last two. range(0, 10, 3) gives 0 3 6 9 — the next would be 12, which is past 10, so it stops. And range(5, 0, -1) gives 5 4 3 2 1 — 0 never appears, because the end is excluded here too.
Why is the end excluded? Because it makes the arithmetic easy. How many numbers inrange(0, 5)?5 - 0, so five. Inrange(3, 8)?8 - 3, five. Subtract and you have the count, with no wondering whether to add one. And two ranges placed side by side —range(0, 5)andrange(5, 10)— miss nothing and repeat nothing.
When you want one to ten
This mistake happens often enough to deserve its own section:
print("Wrong — stops at 9:")
for i in range(1, 10):
print(i, end=" ")
print()
print("Right — includes 10:")
for i in range(1, 11):
print(i, end=" ")
print()Wrong — stops at 9:
1 2 3 4 5 6 7 8 9
Right — includes 10:
1 2 3 4 5 6 7 8 9 10The rule in one line: write one more than the last number you want as the stop.
Accumulating — now the easy way
total = 0
for number in range(1, 6):
total = total + number
print("Sum of 1 to 5:", total)Sum of 1 to 5: 15Compare it with the while version of the same job: no counter to create, none to increment, no risk of an infinite loop. Only the accumulator still has to start outside the loop, exactly as before.
Looping over text
for does not only walk over numbers — it walks over text, character by character:
word = "Python"
for letter in word:
print(letter, end="-")
print()
vowel_count = 0
for letter in "programming":
if letter in "aeiou":
vowel_count = vowel_count + 1
print("Vowels:", vowel_count)P-y-t-h-o-n-
Vowels: 3There is no range here, because none is needed — for letter in word walks the characters directly. It is simpler than doing index arithmetic, and there is no IndexError to risk.
When you need both the position and the character, enumerate() exists, but that belongs to the mission on lists.
break and continue work here too
Exactly as they did in a while:
for number in range(1, 20):
if number % 7 == 0:
print("First multiple of 7:", number)
breakFirst multiple of 7: 7Choosing between for and while
Ask one question: is the number of repetitions known before the loop starts?
If yes, for:
- Run five times
- Go from 1 to 100
- Look at every character of a word
- Do something with every item in a list
If no, while:
- Keep asking until the input is valid
- Run until the person types
quit - Read while there are lines left in a file
When in doubt, choose for. The reason is simple: a for loop is guaranteed to end, and a while loop is not. Where both would work, the one that allows fewer mistakes is the better choice.
A complete example
multiplication.py:
# Print a multiplication table, then a small summary
number = int(input("Which table? "))
upto = int(input("Up to? "))
print()
print(f"--- Table of {number} ---")
total = 0
for i in range(1, upto + 1):
result = number * i
total = total + result
print(f"{number} x {i:2} = {result:4}")
print()
print(f"Rows : {upto}")
print(f"Sum : {total}")
print(f"Average : {total / upto:.2f}")Which table? 7
Up to? 5
--- Table of 7 ---
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
Rows : 5
Sum : 105
Average : 21.00Three things to notice. First, range(1, upto + 1) — reaching upto required writing one more. Second, {i:2} and {result:4} — inside an f-string you can state how much width a number should occupy, which keeps the columns straight. Third, total starts outside the loop and grows inside — the same accumulator as before.
And ask yourself one question: what happens if the person answers 0 to Up to? The range(1, 1) produces no numbers at all, so the loop never runs — and then total / upto divides by zero. It is the same lesson as the previous mission: before using what a loop accumulated, check that it accumulated something.
When it breaks
The last number is missing range(1, 10) finishes at 9. Add one to the stop: range(1, 11).
TypeError: 'float' object cannot be interpreted as an integer range() accepts whole numbers only. range(2.5) or range(1, n / 2) will not run — convert with int(), or divide with //.
SyntaxError: expected ':' The colon at the end of the for line is missing.
IndentationError: expected an indented block after 'for' statement The line inside the loop was not indented.
The loop never ran The range is empty. range(5, 0) produces nothing — to count downwards you need the third argument: range(5, 0, -1).
The total is 0 after the loop The total = 0 line has slipped inside the loop, so it resets every pass. It has to be outside.
A variable from inside the loop is needed outside, but raises NameError The range was empty, so the loop never ran and the variable was never created. Give it a starting value before the loop.
Step 4 of 6 — Predict
Check your understanding
What does this loop print?
for i in range(1, 5):
print(i, end=" ")- A1 2 3 4
- B1 2 3 4 5
- C0 1 2 3 4
- D1 2 3
The third argument sets the step. What is the output?
for i in range(0, 10, 3):
print(i, end=" ")- A0 3 6 9
- B0 3 6 9 12
- C3 6 9
- D0 1 2 3 4 5 6 7 8 9
The intent was the sum of 1 to 10, which is 55. It prints 45. Why?
total = 0
for number in range(1, 10):
total = total + number
print("Sum of 1 to 10:", total)- A`range(1, 10)` finishes at `9` and leaves out `10` — it needs `range(1, 11)`
- B`total` was initialised outside the loop when it should be inside
- CUsing a `while` loop instead of `for` would give the right answer
- DIt should be `total + i` rather than `total + number`
Answering needs an account
Sign in to check your answers
The questions are above, and working them out in your head is the part that matters. Sign in to see the answers, the explanations and the three-level hints.
Your turn
Write a file called stars.py that takes a number and prints a triangle. Given 5:
*
**
***
****
*****Then add these three things:
- Print the total number of stars at the bottom (15 for an input of 5)
- Print the triangle upside down as well — five at the top, one at the bottom
- Print a version that skips the even-numbered rows (use
continue)
There is an easy way to check the first one — work out the sum of 1 to 5 by hand and see whether your program agrees. And remember "*" * i? Building a row of stars needs no loop inside the loop.
Step 6 of 6
Stretch — the chapter quiz
Ten questions from easy to hard. The last ones are difficult on purpose.
Sign in to take the quiz