MOD-15 · Sequence #15 · Control Flow

Python For Loops & Range

Python for loops are sequence iterators (equivalent to foreach in other languages). Instead of managing loop index variables, Python uses iterables, range generators, enumerate for index tracking, and zip for parallel iteration.

Live Interactive Code Snippet (Python 3.12 CPython WASM) Open in Practice Mode →
names = ["Alice", "Bob"]
for idx, name in enumerate(names, 1):
    print(f"{idx}: {name}")

Core Principles & Mental Models

1. The range() Lazy Sequence Generator

O(1) Memory Regardless of Size

  • In Python 3, `range(start, stop, step)` does not generate a list of numbers in memory; it returns a lazy range object.
  • Memory consumption of `range(1_000_000)` is O(1) constant 48 bytes because numbers are generated on demand during iteration.
import sys
r1 = range(10)
r2 = range(10_000_000)
print("Size of range(10):", sys.getsizeof(r1), "bytes")
print("Size of range(10M):", sys.getsizeof(r2), "bytes")
💡 Key Takeaway: range() produces numbers on demand with O(1) memory footprint.

2. Idiomatic Iteration: enumerate() and zip()

Eliminating Manual Index Variables

  • `enumerate(iterable, start=0)` yields (index, item) pairs, eliminating manual counter variables.
  • `zip(seq1, seq2)` iterates through multiple sequences in lockstep, terminating at the shortest sequence.
names = ["Alice", "Bob", "Charlie"]
scores = [95, 88, 92]

for i, (name, score) in enumerate(zip(names, scores), start=1):
    print(f"Rank {i}: {name} -> {score}")
💡 Key Takeaway: Never write `for i in range(len(lst)):` when `enumerate(lst)` is available.

Interactive Walkthrough Examples

Iterating Over Multiple Sequences in Parallel (Basic)

Using zip to aggregate student names, subjects, and test grades.

students = ["Alice", "Bob"]
subjects = ["Math", "Physics"]
grades = ["A", "B+"]

for s, sub, g in zip(students, subjects, grades):
    print(f"{s} got {g} in {sub}")

Explanation: zip aggregates elements from each iterable until the shortest iterable is exhausted.

Common Misconceptions & Exam Traps

Common Pitfall: Writing C-Style Index Loops in Python

Index-based access is slower and introduces unnecessary subscripting overhead.

Buggy Code
items = ["a", "b", "c"]
for i in range(len(items)):  # Unpythonic & error-prone
    print(i, items[i])
Correct Solution
items = ["a", "b", "c"]
for i, val in enumerate(items):  # Idiomatic Python
    print(i, val)

Exam Trap Note: Undergraduate coding interviews heavily penalize `for i in range(len(x)):` when `enumerate()` is appropriate.

Conceptual Knowledge Self-Check Quiz

Q1: What does `enumerate(["cat", "dog"], start=1)` yield on its first iteration?

  1. ("cat", 1)
  2. (1, "cat")
  3. [0, "cat"]
  4. 1

enumerate yields a tuple of `(index, element)`. With start=1, the first yield is `(1, "cat")`.

Algorithmic Practice Challenges

Idiomatic Best Practices

  • ✅ Use `for item in collection:` to iterate directly over items.
  • ✅ Use `for i, item in enumerate(collection):` when you need indices.
  • ✅ Use `zip(strict=True)` in Python 3.10+ if sequences must have equal length.

All 26 Curriculum Modules