Learning

Iterators & Iterator Protocol

Iterators & Iterator Protocol

Iterator Protocol

python
class CountUp: def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current > self.end: raise StopIteration value = self.current self.current += 1 return value for n in CountUp(1, 5): print(n, end=' ') # 1 2 3 4 5

iter() and next() Built-ins

python
class Squares: def __init__(self, n): self.n = n self.i = 0 def __iter__(self): return self def __next__(self): if self.i >= self.n: raise StopIteration self.i += 1 return (self.i - 1) ** 2 sq = Squares(4) it = iter(sq) # Get the iterator print(next(it)) # 0 print(next(it)) # 1 print(next(it)) # 4 print(next(it)) # 9 # print(next(it)) # StopIteration

Iterator is Exhausted After One Pass

python
class MyRange: def __init__(self, n): self.n = n self.i = 0 def __iter__(self): return self def __next__(self): if self.i >= self.n: raise StopIteration val = self.i self.i += 1 return val r = MyRange(3) print(list(r)) # [0, 1, 2] print(list(r)) # [] — exhausted!

Fix: Separate Iterable from Iterator

python
class RangeIterable: def __init__(self, n): self.n = n def __iter__(self): return RangeIterator(self.n) # NEW iterator each time! class RangeIterator: def __init__(self, n): self.n = n self.i = 0 def __iter__(self): return self def __next__(self): if self.i >= self.n: raise StopIteration val = self.i self.i += 1 return val r = RangeIterable(3) print(list(r)) # [0, 1, 2] print(list(r)) # [0, 1, 2] — works again!

Custom Reverse Iterator

python
class Reverse: def __init__(self, data): self.data = data self.index = len(data) def __iter__(self): return self def __next__(self): if self.index <= 0: raise StopIteration self.index -= 1 return self.data[self.index] for ch in Reverse('hello'): print(ch, end='') # olleh
Key Rules
  • •Iterator protocol requires exactly TWO methods: __iter__() returning self, and __next__() returning next value
  • •Raise StopIteration from __next__() to signal the end — for loops handle this automatically
  • •An iterator is EXHAUSTED after one full traversal — calling list() on it twice gives empty list second time
  • •To make a reusable iterable, separate the iterable (__iter__ returns new iterator) from the iterator
  • •iter(obj) calls obj.__iter__(), and next(it) calls it.__next__()
  • •Any object with __iter__ + __next__ works with for loops, list(), tuple(), set(), sum(), and all() built-ins
Your Task

Create a `FibIterator` class that generates Fibonacci numbers up to a `limit` parameter. Implement the full iterator protocol. Create a `FibIterable` class whose `__iter__` returns a NEW `FibIterator` each time (so it's reusable). Demonstrate: iterating with for loop, converting to list twice (both should work), and using next() manually.

EditorPython · JSX
PreviewUpdates on Run Tests
Loading preview…
Tests
Should define FibIterator with __iter__ and __next__
Should raise StopIteration when over limit
Should define FibIterable class
FibIterable.__iter__ should return new FibIterator
Should use next() built-in manually
Should demonstrate list() conversion