Iteration is what makes programs worth writing. A loop lets ten lines of code process ten values or ten million, with no change. Python has two kinds, and choosing the right one removes most loop bugs before you write them: use for when you know how many times, and while when you are waiting for a condition.
The for loop
| Python | Values of i |
|---|---|
for i in range(5): | 0, 1, 2, 3, 4 — five values, starting at 0 |
for i in range(1, 6): | 1, 2, 3, 4, 5 — stops BEFORE 6 |
for i in range(0, 20, 5): | 0, 5, 10, 15 — step of 5 |
for i in range(10, 0, -1): | 10, 9, 8 … 1 — counting down |
for mark in marks: | Each item of the list marks in turn |
range(1, 6) gives 1, 2, 3, 4, 5 — not 6. This half-open convention means range(n) gives exactly n values and range(len(items)) gives exactly the valid indexes. It is also the single most common source of off-by-one errors, so whenever a loop runs one time too few, check this first.The while loop
| Python | What it does |
|---|---|
count = 0 | Initialize BEFORE the loop — forget this and the first test fails |
while count < 5: | Test the condition before every pass |
print(count) | The body |
count = count + 1 | Update the variable in the condition — forget this and the loop never ends |
Counters and accumulators
Two patterns cover most loop work. A counter starts at 0 and increases by 1 whenever something of interest happens — it answers "how many". An accumulator starts at 0 and adds a value each pass — it answers "what is the total". Both must be initialized before the loop, never inside it: putting total = 0 inside the body resets it every pass, and the final answer ends up being just the last value.
| Python | What it does |
|---|---|
total = 0 | Accumulator, initialized OUTSIDE the loop |
count = 0 | Counter, also outside |
for mark in marks: | Visit each mark |
total = total + mark | Accumulate the sum |
if mark >= 50: | Test each one |
count = count + 1 | Count the passes |
average = total / len(marks) | Use the results after the loop finishes |
print indented inside the loop runs every pass. The same print at the outer level runs once, after the loop. "My program prints the total ten times" is almost always a line indented one level too far.Nested loops
A loop inside a loop runs the inner loop completely for every single pass of the outer loop. Two nested loops of ten passes each means one hundred passes of the inner body — which is how a nested loop can be slow without looking slow. They are the natural fit for grids and tables: the outer loop walks the rows and the inner loop walks the columns within each row.
| Python | What it does |
|---|---|
for row in range(1, 4): | Runs 3 times: row = 1, 2, 3 |
for col in range(1, 4): | Runs 3 times for EACH row — 9 passes total |
print(row * col, end=" ") | Prints one cell, staying on the same line |
print() | Outside the inner loop: ends the row |
break exits the loop immediately, which is how you stop searching once you have found what you wanted. continue skips the rest of the current pass and starts the next one. Both are useful, but a loop with several breaks scattered through it becomes hard to reason about — prefer a clear condition where you can.