backend / python core / 10_iterator_vs_generator.md

Difference Between Iterators and Generators

3 interview angles 2 min read source

Difference Between Iterators and Generators

1. Iterators

  • Definition: Objects in Python that implement the __iter__() and __next__() methods to enable iteration over their elements.
  • Key Features:
    • Can be created using classes.
    • Consumes more memory if all elements are stored in memory.
  • Example:
    class Counter:
        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
            self.current += 1
            return self.current - 1
    
    counter = Counter(1, 5)
    for num in counter:
        print(num)

2. Generators

  • Definition: A type of iterator created using a function with the yield keyword. They produce items lazily, one at a time, only when requested.
  • Key Features:
    • Created using functions.
    • More memory-efficient as they do not store all values in memory.
  • Example:
    def fibonacci(n):
        a, b = 0, 1
        for _ in range(n):
            yield a
            a, b = b, a + b
    
    for num in fibonacci(5):
        print(num)

3. Key Differences

Feature Iterators Generators
Creation Defined using classes. Defined using functions and yield.
Memory Usage May use more memory (stores all items). More memory-efficient (lazy evaluation).
Syntax Complexity Requires defining __iter__() and __next__(). Simpler syntax with yield.
Reusability Can be reused by resetting the state. Cannot be reused; needs recreation.
print("\nIterator\n")
class Counter:
      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
          self.current += 1
          return self.current - 1

counter = Counter(1, 5)
for num in counter:
      print(num)

print("\nGenerator\n")
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

for num in fibonacci(5):
    print(num)

Interview angle

  • “Iterator versus generator?” - every generator is an iterator; not every iterator is a generator. A generator is the concise way to produce one, created by a function with yield or a generator expression.
  • “What’s the memory difference in practice?” - a list comprehension materialises everything; a generator expression yields one item at a time. Swapping brackets for parentheses in sum(...) over a large sequence removes the intermediate list entirely.
  • “What can’t a generator do?” - be re-iterated, indexed, or measured with len(). Once exhausted it stays exhausted, which is the bug when you loop over the same generator twice and the second loop silently does nothing.