Matheion

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)) using enumerate where possible.
  • Count iterations of a nested double loop before running.
  • Explain difference between range(10) max element vs len(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. 1.Which values does `range(3, 10, 2)` produce?

  2. 2.How many times does the innermost `print` run? ```python for i in range(3): for j in range(2): print(i, j) ```

  3. 3.What does `enumerate(['a', 'b', 'c'])` give you on each iteration?

  4. 4.You are summing numbers in a loop with `total = total + n`. Where must `total = 0` go?

  5. 5.To print each fruit in `fruits = ['apple', 'pear']`, which loop is the most idiomatic Python?