Unit 05 · lesson
Loop Forensics
Core path: 30 minutes
A loop is easy to read badly.
You see the same three lines inside the body and your brain compresses them into "this repeats." Python does not experience a loop that way. It experiences a sequence of separate iterations, each with its own current values.
When a loop goes wrong, the fastest way out is usually to stop thinking about "the loop" and inspect one iteration at a time.
Trace the state, not the indentation
Consider:
total = 0
for number in range(1, 4):
total = total + number
print(number, total)
Do not run it yet.
Trace it:
| Iteration | number | total before | total after |
|---|---|---|---|
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 3 |
| 3 | 3 | 3 | 6 |
The line:
total = total + number
means:
- read the current
total; - read the current
number; - add them;
- assign the new result back to
total.
That state survives into the next iteration.
Re-run the accumulator evidence surface from Lesson 2 if you need to inspect that state change line by line:
Run the code to see output.
The intermediate prints are intentional. They make the loop state visible instead of hiding the accumulator.
Find the off-by-one before Python does exactly what you wrote
Compare:
range(1, 5)
and:
range(1, 6)
The first produces:
1 2 3 4
The second produces:
1 2 3 4 5
The stop value is excluded.
Use the range comparison surface to test that boundary directly:
Run the code to see output.
Predict every sequence before running. Then change one stop value by 1 and identify the exact off-by-one effect.
That rule is simple. The bugs it causes are not always obvious.
Suppose the requirement is:
Process devices 1 through 10.
Then:
range(1, 10)
is wrong. Device 10 is never processed.
The program may still look like it worked because nine devices were processed successfully.
Counters can be correct while the program is wrong
Look at:
warning_count = 0
for battery in [80, 9, 60, 5]:
if battery <= 10:
warning_count += 1
print(warning_count)
The correct result is 2.
Now move the increment outside the condition:
warning_count = 0
for battery in [80, 9, 60, 5]:
if battery <= 10:
print("warning")
warning_count += 1
The program prints the warning messages correctly but reports 4 warnings.
Same loop. Wrong state update.
Indentation is part of the logic.
Infinite loops are usually state problems
Consider:
command = ""
while command != "quit":
print("waiting")
What variable controls termination?
command.
What line changes command inside the loop?
None.
So the loop has no path to a different condition result.
A correct version might be:
command = ""
while command != "quit":
command = input("> ").lower()
Now each iteration can change the value that the condition depends on.
That is the question to ask whenever a while loop refuses to stop:
What state could make this condition false, and where does that state change?
Build a trace from your monitor
Choose one batch from Lesson 4 with at least three devices.
Trace:
iteration number
current device
battery
current warning_count before evaluation
branch selected
warning_count after evaluation
total_battery after update
Then answer:
- Which variables reset each iteration?
- Which variables persist across iterations?
- Which variable controls the outer
whileloop? - What exact update allows the outer loop to stop?
A quick prediction trap
What does this print?
for number in range(3):
print(number)
Not 1, 2, 3.
It prints:
0
1
2
Python is not being weird. range(3) means start at the default 0 and stop before 3.
The machine follows the rule. Your mental shortcut is the thing under investigation.
The loop you can explain is the loop you control
By the end of the week, you should be able to look at a loop and identify:
- the condition or range that controls repetition;
- the variable that changes each iteration;
- state that survives across iterations;
- the stop condition;
- one likely off-by-one boundary; and
- what one iteration does before the next begins.
That is a better skill than memorizing for and while syntax separately.
The syntax is small. The state is where the bugs hide.
Reader workbench
Watch loop state accumulate
This is the Unit's one-file practice surface. Read the code, predict one result, run it, then change a value, input, condition, or boundary and explain why the evidence changed. Multi-file projects, Git, terminals, packages, and live services still belong in the full development workspace.
One line is returned for each input() call, in order.
Run the code to see output.
This runs in an isolated Python worker in your browser. Your edits stay in this browser until you reset them.