Iterators & Itertools
The Iterator Protocol is the invisible force that powers Python. Every time you use a for loop, a list comprehension, or a map() function, you are using iterators.
Understanding iterators allows you to create your own “loopable” objects and process infinite streams of data with zero memory overhead.
1. Iterable vs. Iterator
Section titled “1. Iterable vs. Iterator”These two terms sound similar but are distinct roles in the protocol.
The Iterable (The Container)
Section titled “The Iterable (The Container)”An object that can “produce” an iterator. It implements the __iter__ method. Examples: Lists, Strings, Tuples.
The Iterator (The Pointer)
Section titled “The Iterator (The Pointer)”The object that actually does the work. It remembers where it is in the collection and implements:
__next__: Returns the next value or raisesStopIteration.__iter__: Returns itself (so iterators can also be used in loops).
data = [10, 20]# 1. Get the iterator from the iterableit = iter(data)
# 2. Manually fetch itemsprint(next(it)) # 10print(next(it)) # 20# print(next(it)) # Raises StopIteration2. Creating Custom Iterators
Section titled “2. Creating Custom Iterators”By implementing the protocol, you can make your classes behave like built-in lists.
class Countdown: def __init__(self, start): self.current = start
def __iter__(self): return self
def __next__(self): if self.current < 0: raise StopIteration val = self.current self.current -= 1 return val
for n in Countdown(3): print(n)3. Power Tool: The itertools Module
Section titled “3. Power Tool: The itertools Module”The Standard Library’s itertools module provides specialized iterators for complex tasks.
Infinite Iterators
Section titled “Infinite Iterators”count(start, step): Returns numbers forever.cycle(iterable): Repeats a collection forever.
Combinatorial Iterators
Section titled “Combinatorial Iterators”permutations(p, r): All possible orderings.combinations(p, r): All possible groupings (order doesn’t matter).
import itertools
# Create an infinite counterfor i in itertools.count(10, 5): if i > 25: break print(i) # 10, 15, 20, 254. Under the Hood: Memory Efficiency
Section titled “4. Under the Hood: Memory Efficiency”Iterators follow the “Pull” model. Values are not generated until you “pull” them using next().
This is why you can have an infinite iterator like itertools.count(). It doesn’t store “infinity” in RAM; it only stores the current number and a recipe for how to get the next one. This is the foundation of high-performance data processing in Python.
5. Summary Table: The Iterator Protocol
Section titled “5. Summary Table: The Iterator Protocol”| Method | Role |
|---|---|
iter(obj) | Calls obj.__iter__(). Returns an iterator. |
next(it) | Calls it.__next__(). Returns the next item. |
StopIteration | The signal that there are no more items. |