P1.6 — Repeating with Loops¶
What you'll learn
- Why loops exist: to repeat a block of steps without copying it.
forto repeat a set number of times, andwhileto repeat until a condition changes.- That the indented loop body runs once per pass (per iteration).
- The off-by-one pitfall (
range(n)stops beforen) and the infinite-loop pitfall.
How it applies
- Loops replace copy-paste. Doing something 100 times by writing 100 lines is unworkable and impossible to change; a loop writes the step once and repeats it, so the count can even be decided while the program runs.
- Off-by-one is the loop bug. Running one time too many or one too few — missing the last item, or going one past the end — is the single most common loop mistake. Knowing exactly where a loop starts and stops is the cure.
- A loop that never stops freezes the program. A
whilewhose condition never becomes false repeats forever, and the program hangs. Everywhileneeds something inside it that eventually makes the condition false. - The body runs per pass. Anything inside the loop happens on every iteration; anything outside happens once. Putting a line in or out of the loop body changes how many times it runs.
Concepts¶
Why loops¶
Suppose you want to print Tick three times. You could write three print lines — but for 100 times,
or a number not known until the program runs, that falls apart. A loop writes the repeated step
once and tells the computer how many times, or how long, to repeat it. The repeated, indented lines
are the loop body, and one pass through the body is one iteration.
for: repeat a set number of times¶
A for loop repeats its body for each number in a range:
range(3) produces the numbers 0, 1, 2 — three values — so the body runs three times, printing
Tick thrice. The variable i holds the current number each pass, which is often useful:
The crucial detail: range(n) stops before n. range(3) is 0, 1, 2 — it does not include
3. So range(3) runs three times (counting the 0), and the largest value is 2. This is the home
of the off-by-one bug: if you wanted the numbers 1, 2, 3, range(3) gives the wrong set — you would
use range(1, 4) (start at 1, stop before 4).
while: repeat until a condition changes¶
A while loop repeats its body as long as a condition is true, rechecking before each pass:
var count := 3
while count > 0:
print(count)
count = count - 1 # this is what eventually stops the loop
print("Liftoff!")
This prints 3, 2, 1, then Liftoff!. Trace it: count is 3 (>0, run body, print 3, count
becomes 2); 2 (>0, print, becomes 1); 1 (>0, print, becomes 0); 0 (0 > 0 is false → stop).
The line count = count - 1 is essential: without something inside the body that moves the condition
toward false, count > 0 would stay true forever and the loop would never end — an infinite loop
that freezes the program. Every while needs a way out.
Use for when you know the count or are stepping through a range; use while when you repeat until
some condition changes and you do not know in advance how many passes that takes.
Example
The loop body runs per pass; code outside runs once:
var total := 0
for i in range(5): # i is 0,1,2,3,4 — five passes
total = total + i # inside: runs every pass, adding 0,1,2,3,4
print(total) # outside: runs once, after the loop → 10
The addition happens five times (once per iteration), accumulating 0+1+2+3+4 = 10; the print
is outside the loop body (not indented under for), so it runs a single time at the end. Move that
print inside the loop and it would print five times, once per pass — same lines, different
behavior, decided entirely by whether the line is in the body.
Walkthrough¶
Use your P1.1 script setup.
- Write
for i in range(3): print("Tick"). Run; confirm threeTicks. Then printiinstead of"Tick"and confirm it shows0, 1, 2— note it stops at2, not3. - Make it count
1, 2, 3by usingrange(1, 4). Confirm. This is the off-by-one fix. - Write the
whilecountdown from3withcount = count - 1inside. Run; confirm3 2 1 Liftoff!. Then remove thecount = count - 1line and run — the program hangs (an infinite loop). Stop it (close the window / press F8), and put the line back. You have now met both loop pitfalls. - Accumulate: sum
0through4with aforloop and atotalvariable, printingtotalafter the loop. Confirm10. Then move theprintinside the loop and watch it print five times.
Optional sanity check
Predict the output of for i in range(4): print(i) before running. If you said 0 1 2 3 (four
numbers, stopping before 4), you have the range rule. If you expected 1 2 3 4 or 0 1 2 3 4, run
it and reconcile — that gap is exactly the off-by-one most beginners hit once and then never forget.
Self-check quiz¶
Q1 — How many times does the body of for i in range(3): run, and what values does i take?
A. 3 times; i is 1, 2, 3.
B. 3 times; i is 0, 1, 2 (range(3) stops before 3).
C. 4 times; i is 0, 1, 2, 3.
D. Once.
Reveal answer
B. range(3) produces 0, 1, 2 — three values, stopping before 3 — so the body runs
three times with those values. A starts at the wrong number. C includes 3, the off-by-one
error. D ignores that it is a loop.
Q2 — What makes a while loop eventually stop?
A. It always stops after 10 passes.
B. Something inside the body changes a value so the condition becomes false.
C. The else block.
D. Nothing — while loops run forever.
Reveal answer
B. A while repeats while its condition is true; the body must change something (like
decrementing a counter) so the condition eventually becomes false. A invents a fixed limit. C
confuses loops with decisions. D is the infinite-loop bug, not how a correct while behaves.
Q3 — A print is written inside a loop body that runs 5 times. How many times does it print?
A. Once, after the loop. B. 5 times — once per iteration, because it is in the body. C. Never. D. Twice.
Reveal answer
B. Code inside the loop body runs once per pass, so a print in a 5-iteration loop prints 5
times. A describes a print placed outside (un-indented). C and D ignore how many times the
body runs.
Integration question¶
Q4 — open
Combine a loop and a decision (P1.5): print every number from 1 to 10, but for each one print
"even" if it is divisible by 2 and "odd" otherwise. Sketch the code, state how many times the
loop body runs and what range you used, and explain where the decision goes relative to the loop —
then name the one off-by-one mistake most likely to make this print the wrong set of numbers.
Reveal expected answer
Use a for over range(1, 11) so the values are 1 through 10 (start at 1, stop before
11), and put an if/else inside the loop body so the decision is made once per number:
for n in range(1, 11):
if n % 2 == 0: # divisible by 2 → no remainder
print(n, " even")
else:
print(n, " odd")
The body runs 10 times, once per value of n. The decision lives inside the loop body
(indented under for) so it evaluates for each n individually; if it were outside, it would
run only once, after the loop, against the final value. The most likely off-by-one mistake is
the range: range(10) would give 0–9 (missing 10 and wrongly including 0), and
range(1, 10) would stop at 9 (missing 10). Because range stops before its second number,
getting 1 through 10 requires range(1, 11) — the classic place a loop prints one number too
few or starts one too low.