MA-PY1 · Module 2.1
For loops and iteration
Topics: For loops · range · Iteration
Overview
Module 2.1 — For loops and iteration
Scroll Core ideas → worked snippets → Practice (quiz). Attempt each question before Discuss / reveal. Use any Python REPL, script, or notebook you like.
Concepts
Core ideas — for, range, and iteration idioms
Python’s for loop is a foreach: it visits each element yielded by an iterable in order. You rarely need manual index juggling—enumerate gives (index, value) pairs when you need both.
What "iterable" means
An iterable is simply anything you can step through one item at a time. A list hands you its elements; a string hands you its characters; range(5) hands you the numbers 0,1,2,3,4; an open file hands you its lines. The for loop does not care which of these it is — it just keeps asking "give me the next item" until there are none left. That uniformity is the whole point: you learn one loop shape and it works on every collection.
So when you read for x in things:, picture Python pulling items out of things one by one and binding each to x before running the body. You almost never need to track a numeric index by hand.
When should you reach for for rather than while? Use for when you already know what you're stepping through (a collection or a fixed count). Reserve while for "keep going until some condition changes," where there is no obvious collection to walk.
range
range(stop)→0 … stop-1(exclusive stop).range(start, stop)inclusive start, exclusive stop.range(start, stop, step)step may be negative for downward counts (range(5, 0, -1)).
range(...) behaves like an immutable sequence conceptually—it does not build a gigantic list eagerly (memory friendly).
Accumulator pattern
Initialise before, update inside, use after:
total = 0
for value in readings:
total += value
Same pattern for product, counts, building output lists (results.append(transform(x))).
When to combine enumerate
for i, token in enumerate(tokens):
print(i, token)
Cleaner than range(len(tokens)) when you only index to fetch tokens[i].
Nested loops
A loop inside another loop runs the whole inner loop once for every step of the outer loop. The counts therefore multiply: outer n steps × inner m steps ⇒ up to n*m passes through the inner body. Keep that in mind before putting heavy work inside nested loops.
Trace this small example by hand before running it:
for row in range(2):
for col in range(3):
print(row, col)
The outer loop fixes row = 0, then the inner loop walks col through 0,1,2; then row = 1 and the inner loop walks 0,1,2 again. That is 2 × 3 = 6 lines:
| Pass | row | col | printed |
|------|-------|-------|---------|
| 1 | 0 | 0 | 0 0 |
| 2 | 0 | 1 | 0 1 |
| 3 | 0 | 2 | 0 2 |
| 4 | 1 | 0 | 1 0 |
| 5 | 1 | 1 | 1 1 |
| 6 | 1 | 2 | 1 2 |
Notice the inner variable races through all its values before the outer one moves a single step. Building this table on paper for any nested loop is the surest way to predict its output.
Iterable unpacking (primer)
Comma-separated assignment works with for unpacking:
pairs = [(0, 'a'), (1, 'b')]
for i, ch in pairs:
...
We'll reuse this with functions returning tuples and dictionaries later.
Self-study checklist
- Rewrite
for i in range(len(xs))usingenumeratewhere possible. - Count iterations of a nested double loop before running.
- Explain difference between
range(10)max element vslen(range(10)).
Examples
Worked snippets — iterating with intention
Basic for over a list
for note in ["do", "re", "mi"]:
print(note.upper())
range patterns
print(list(range(4))) # 0..3
print(list(range(2, 7, 2))) # 2,4,6
print(list(range(5, 0, -1))) # 5 down to 1
Accumulator: sum and count
values = [3, 1, 4, 1, 5, 9]
total = 0
count = 0
for v in values:
total += v
count += 1
mean = total / count
print(mean)
enumerate for index + value
words = ["fix", "upper", "case"]
for i, w in enumerate(words):
print(i, w.upper())
Optional start index: enumerate(words, start=1) for human numbering.
Building a new list in a loop
src = [1, -2, 3, -4]
abs_vals = []
for x in src:
abs_vals.append(abs(x))
print(abs_vals)
Then compare with comprehension: [abs(x) for x in src].
Nested loop iteration count
for i in range(3):
for j in range(2):
print(i, j)
Eight lines? No—3 * 2 = 6 prints; trace rows by outer i.
Unpacking in for
coords = [(0, 0), (1, 2), (3, 4)]
for x, y in coords:
print(x + y)
while vs for transformation (idea)
for x in range(5, 0, -1):
print(x)
is often clearer than hand-rolling index decrements—prefer for when the sequence is known.
Practice check — for loops and iteration
Multiple-choice check from the Matheion app lesson. Pick an answer for each question, then submit.
1.Which values does `range(3, 10, 2)` produce?
2.How many times does the innermost `print` run? ```python for i in range(3): for j in range(2): print(i, j) ```
3.What does `enumerate(['a', 'b', 'c'])` give you on each iteration?
4.You are summing numbers in a loop with `total = total + n`. Where must `total = 0` go?
5.To print each fruit in `fruits = ['apple', 'pear']`, which loop is the most idiomatic Python?