For Loops, Range Generators & Iterator Protocols
Deep dive into deterministic counting loops, generator ranges, iterator protocols (__iter__ / __next__), index vs value iteration, and nested iteration complexity.
1. The Iterator Protocol & Memory Efficiency
A for loop in modern computer science is fundamentally an abstraction over an Iterator Protocol. Rather than loading an entire sequence into memory simultaneously, an iterator yields one element at a time on demand via constant O(1) space pointer increments.
Range Generators vs Full Sequence Materialization:
In Python 3, range(1, 10_000_000) consumes only 48 bytes of memory because it calculates values algorithmically using start, stop, and step arithmetic without allocating an array of 10 million integers in heap RAM.
1matrix = [2 [1, 2, 3],3 [4, 5, 6],4 [7, 8, 9]5]67# Flatten matrix and compute row sums using for loops8row_sums = []9for r_idx, row in enumerate(matrix):10 current_sum = 011 for val in row:12 current_sum += val13 row_sums.append(current_sum)14 print(f'Row {r_idx} Sum: {current_sum}')1516print('Total Processed Rows:', len(row_sums))
Row 0 Sum: 6 Row 1 Sum: 15 Row 2 Sum: 24 Total Processed Rows: 3
2. Nested Loops & Asymptotic Big-O Analysis
When loops are nested, the total operations executed equals the product or summation of their iteration spaces.
- Square Grid: Outer loop runs
Ntimes; inner loop runsMtimes -> Total Time Complexity =O(N * M). - Triangular / Combinatorial: Outer loop runs
ifrom0toN-1; inner loop runsjfromi + 1toN-1. The number of steps is(N * (N - 1)) / 2, which simplifies asymptotically toO(N^2).
Loop Pattern Complexity Benchmarks
| Structure | Inner Operations | Total Operations | Big-O Time |
|---|---|---|---|
| Single Linear Scan | O(1) constant | N steps | O(N) Linear |
| Divide-and-Conquer Step (Halving) | i = i / 2 | log2(N) steps | O(log N) Logarithmic |
| All Element Pairs (Nested) | O(1) comparison | N * (N - 1) / 2 steps | O(N^2) Quadratic |
| All Triplet Combinations | O(1) check | N * (N - 1) * (N - 2) / 6 | O(N^3) Cubic |
Quick Syntax & Reference Sheet
| Concept / Rule | Syntax / Usage |
|---|---|
| Enumerate Traversal | for idx, val in enumerate(items):
# access both index and item |
| Triangular Pair Iteration | for i in range(len(arr)):
for j in range(i + 1, len(arr)):
# all unique pairs (i, j) |
Common Pitfalls & Developer Mistakes
Modifying a Collection While Iterating Over It
Why it happens:
Unnecessary Deep Nesting
Why it happens: