Skip to content

P1.6 — Repeating with Loops

What you'll learn

  • Why loops exist: to repeat a block of steps without copying it.
  • for to repeat a set number of times, and while to repeat until a condition changes.
  • That the indented loop body runs once per pass (per iteration).
  • The off-by-one pitfall (range(n) stops before n) 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 while whose condition never becomes false repeats forever, and the program hangs. Every while needs 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:

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

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:

for i in range(3):
    print(i)        # prints 0, then 1, then 2

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.

  1. Write for i in range(3): print("Tick"). Run; confirm three Ticks. Then print i instead of "Tick" and confirm it shows 0, 1, 2 — note it stops at 2, not 3.
  2. Make it count 1, 2, 3 by using range(1, 4). Confirm. This is the off-by-one fix.
  3. Write the while countdown from 3 with count = count - 1 inside. Run; confirm 3 2 1 Liftoff!. Then remove the count = count - 1 line 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.
  4. Accumulate: sum 0 through 4 with a for loop and a total variable, printing total after the loop. Confirm 10. Then move the print inside 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 09 (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.