A while loop only knows two states of the world: the condition is ==True (do it again) or False== (stop). Every bug, every clever trick, every exam trap lives in when that flip from True to False happens — or fails to happen. This page walks through every shape that flip can take.
Before we start: recall the three ingredients from the parent note — Initialise, Condition, Update (the "I C U" mnemonic). Every example below is really a story about the Update and how it pushes the Condition toward False.
Here is every class of situation a while loop can hand you. Think of it as a checklist — if you can solve one example from each row, you have seen the whole beast.
#
Case class
What makes it distinct
Covered by
A
Counts down to zero
update decreases toward boundary
Ex 1
B
Counts up to a limit
update increases toward boundary
Ex 2
C
Zero-iteration (body never runs)
condition already False on entry
Ex 3
D
Exactly-one iteration (boundary edge)
condition true once, then false
Ex 3
E
Float never lands exactly
== on floats loops forever
Ex 4
F
Unknown count , data-driven
user input decides the length
Ex 5
G
while True + break (deliberate infinite)
condition is a constant
Ex 6
H
Accidental infinite (missing/misplaced update)
update outside the live path
Ex 7
I
Real-world word problem (converging quantity)
model reality as a boundary
Ex 8
J
Exam twist : nested / off-by-one counting
count the checks , not the prints
Ex 9
We now hit all ten cells.
Worked example Example 1 — Rocket countdown
n = 3
while n > 0 :
print (n)
n -= 1
print ( "Go!" )
Forecast: before reading on, guess exactly what prints and how many times the condition n > 0 is checked.
Initialise n = 3.
Why this step? The condition uses n; it must exist first, or Python raises NameError.
Check 3 > 0 → True → print 3, then n becomes 2.
Why this step? Pre-test: we always check before the body runs.
Check 2 > 0 → True → print 2, n → 1.
Check 1 > 0 → True → print 1, n → 0.
Check 0 > 0 → False → exit , print Go!.
Why this step? The update n -= 1 is the engine: each pass drags n one step closer to the boundary 0, guaranteeing a stop.
Verify: prints 3, 2, 1, Go!. The condition was checked 4 times (3 True + 1 final False) to print 3 numbers — the classic off-by-one, see Off-by-one errors .
Worked example Example 2 — Sum first k numbers until we pass a limit
total = 0
k = 0
while total <= 10 :
k += 1
total += k
print (k, total)
Forecast: guess the final k and total.
Start total = 0, k = 0.
Check 0 <= 10 → True → k=1, total=1.
Why this step? The update increases total, so it moves upward toward the boundary — opposite direction from Example 1, same guarantee of stopping.
Continue: k=2,total=3 · k=3,total=6 · k=4,total=10.
Check 10 <= 10 → still True (boundary is inclusive ) → k=5, total=15.
Why this step? <= includes equality, so total=10 does not stop us — a common trap.
Check 15 <= 10 → False → exit.
Verify: 1 + 2 + 3 + 4 + 5 = 15 , and 2 5 ⋅ 6 = 15 . Prints 5 15.
Worked example Example 3 — Boundary edge cases
# Case C: body runs ZERO times
i = 5
while i < 5 :
print ( "C-body" )
i += 1
print ( "C done, i =" , i)
# Case D: body runs EXACTLY once
j = 4
while j < 5 :
print ( "D-body" )
j += 1
print ( "D done, j =" , j)
Forecast: how many times does each body run?
Case C: first check 5 < 5 → False immediately.
Why this step? A while is a pre-test loop — the condition is tested before the body, so if it starts False, the body runs zero times . This is a feature, not a bug.
So C-body never prints; i stays 5.
Case D: check 4 < 5 → True → print D-body, j → 5.
Check 5 < 5 → False → exit. Body ran exactly once .
Verify: C prints only C done, i = 5. D prints D-body once then D done, j = 5.
Common mistake Steel-man: "a loop always runs at least once."
That is a do-while loop (other languages). Python's while is pre-test , so a False-on-entry condition means the body is skipped entirely — Case C proves it.
Worked example Example 4 — Why
== on floats is dangerous
# DANGEROUS (do not run without Ctrl+C ready):
x = 0.0
while x != 1.0 : # will this ever be exactly 1.0?
x += 0.1
Forecast: will x ever equal 1.0 exactly?
In binary floating point, 0.1 cannot be stored exactly.
Why this step? Computers store fractions in base-2; 0.1 is a repeating binary fraction, so it is rounded.
Adding it ten times gives 0.9999999999999999, not 1.0.
Why this step? The tiny rounding errors accumulate; the sum steps over the target instead of hitting it.
So x != 1.0 stays True forever → infinite loop .
Fix: use a < boundary, never ==:
x = 0.0
while x < 1.0 :
x += 0.1
Why this step? < catches any value that crossed the boundary, immune to the last-digit error.
Verify: 0.1 added ten times = 1.0 in float; the < version stops. (See Boolean expressions and comparison operators for choosing the right comparator.)
Worked example Example 5 — Retry until valid input
age = - 1
while age < 0 :
age = int ( input ( "Enter age: " ))
print ( "Thanks, age is" , age)
Forecast: how many loops? (Trick question.)
Initialise age = -1 — a sentinel guaranteeing the condition starts True.
Why this step? We must enter the loop at least once to ask the user; -1 fails age < 0... wait, -1 < 0 is True, so we do enter. Good.
The update is the input() — each round the user supplies a new value.
Why this step? With while the "count" is unknown: it depends on the human, not a number we can predict. This is the core reason while exists (see parent note).
If they type 25, 25 < 0 → False → exit.
Verify: any single non-negative entry stops it; negatives repeat. See input() and type conversion — int() converts the text to a number so the comparison works.
Worked example Example 6 — Menu loop
count = 0
while True : # condition is a constant — never flips
cmd = input ( "> " )
if cmd == "quit" :
break
count += 1
print ( "commands run:" , count)
Forecast: what is the real exit here?
while True has a condition that is always True — it never becomes False on its own.
Why this step? Sometimes the natural stop is an event ("quit"), not a counter. Encoding "loop forever" honestly with True is clearer than a fake condition.
The break statement is the controlled exit.
Why this step? break jumps out immediately, skipping the rest of the body — the deliberate stop. See break and continue statements .
If the user types hi, hi, quit: count becomes 2, then break exits.
Verify: two non-quit commands → count = 2. This is not a bug — the danger is only accidental infinity (next example).
Worked example Example 7 — Update in the wrong place
# BROKEN version:
i = 0
while i < 3 :
if i == 1 :
continue # skips the update below!
print (i)
i += 1
Forecast: at what value of i does this get stuck?
i=0: 0<3 True, not ==1, print 0, i→1.
i=1: 1<3 True, i==1 → continue jumps back to the check without running i += 1.
Why this step? continue skips the rest of the body — including the update — so i is frozen at 1.
Check 1<3 again → still True → continue again → forever. ==Infinite loop stuck at i = 1==.
Fix: update before the continue, or restructure:
i = 0
while i < 3 :
if i != 1 :
print (i)
i += 1 # always runs — on the live path
Why this step? The update must sit on every path the loop can take, or some path never advances.
Verify: fixed version prints 0 and 2 (skips 1), then exits with i = 3. Emergency stop for the broken one: Ctrl + C.
Worked example Example 8 — Bacteria doubling
A dish starts with 50 bacteria and the population doubles every hour . After how many whole hours does it first exceed 1000 ?
pop = 50
hours = 0
while pop <= 1000 :
pop *= 2
hours += 1
print (hours, pop)
Forecast: guess the number of hours before computing.
Model the real quantity pop as the loop variable; the "stop" is a threshold > 1000.
Why this step? We don't know the hour count in advance — it depends on a growth calculation, the textbook signal for while over for.
Trace: 50 → 100 → 200 → 400 → 800 → 1600. Hours: 1,2,3,4,5.
At pop=800, 800 <= 1000 True → one more double → 1600, hours=5.
Check 1600 <= 1000 → False → exit.
Verify: 50 ⋅ 2 5 = 1600 > 1000 , and 50 ⋅ 2 4 = 800 ≤ 1000 , so 5 hours is the first to exceed. Prints 5 1600.
Worked example Example 9 — Count the multiplications
count = 0
i = 1
while i <= 2 :
j = 1
while j <= 3 :
count += 1
j += 1
i += 1
print (count)
Forecast: how many times does the inner body run?
Outer runs for i = 1, 2 → 2 times.
Why this step? i <= 2 starting at 1 gives values 1 and 2 (a 2-count) — off-by-one awareness.
For each outer pass, the inner loop resets j = 1 and runs for j = 1,2,3 → 3 times.
Why this step? Nested loops multiply: total inner runs = 2 × 3 .
So count = 6.
Verify: 2 × 3 = 6 . Prints 6. (Exam trap: if you forgot j = 1 reset, the second outer pass would never run — always reset your inner counter.)
Recall Active recall — cover the answers
In Example 1, how many times is n > 0 checked? ::: 4 times (3 True + 1 final False).
Why does Example 3 Case C print nothing? ::: pre-test loop; condition 5 < 5 is False on entry so the body runs zero times.
Why does the float loop in Example 4 never end? ::: 0.1 isn't stored exactly, so the sum skips over 1.0; == never matches. Use <.
What froze Example 7 at i = 1? ::: continue skipped the i += 1 update, so the condition never advanced.
Bacteria: first hour exceeding 1000 starting at 50, doubling? ::: 5 hours (reaching 1600).
Nested loop count in Example 9? ::: 6 (outer 2 × inner 3).
"Boundary before body" — always ask what value is the condition tested at for the first and last check. Most bugs (zero-run, off-by-one, infinite) hide in those two checks.
deliberate while True Ex6
continue skips update Ex7