0
0
PythonComparisonBeginner · 3 min read

Generator vs Iterator in Python: Key Differences and Usage

In Python, a generator is a special type of iterator that yields items one at a time using yield, saving memory by producing values on demand. An iterator is any object with a __next__() method that returns the next item, often created from iterable objects like lists or custom classes.
⚖️

Quick Comparison

This table summarizes the main differences between generators and iterators in Python.

AspectGeneratorIterator
DefinitionA function or expression that yields items lazily using yieldAn object with __next__() method that returns next item
CreationCreated by generator functions or generator expressionsCreated by calling iter() on iterable or custom class with __iter__() and __next__()
Memory UsageLow memory, produces items on demandDepends on implementation; can store entire data or produce on demand
SyntaxUses yield keywordImplements __next__() and __iter__() methods
ReusabilitySingle-use; exhausted after iterationCan be designed reusable or single-use depending on implementation
Use CaseEfficient looping over large or infinite sequencesGeneral iteration over any iterable data structure
⚖️

Key Differences

Generators are a simpler way to create iterators using functions with the yield keyword. When called, a generator function returns a generator object that produces values one at a time, pausing its state between each yield. This lazy evaluation means generators use less memory and can handle large or infinite sequences efficiently.

On the other hand, an iterator is any object that implements the __next__() method to return the next item and raises StopIteration when done. Iterators can be created manually by defining a class with __iter__() and __next__() methods or automatically by calling iter() on iterable objects like lists or tuples.

While all generators are iterators, not all iterators are generators. Generators provide a concise syntax and automatic state management, whereas iterators offer more control and flexibility but require more code to implement.

⚖️

Code Comparison

Here is an example of a generator that yields squares of numbers from 0 to 4.

python
def square_generator(n):
    for i in range(n):
        yield i * i

for value in square_generator(5):
    print(value)
Output
0 1 4 9 16
↔️

Iterator Equivalent

This is the equivalent iterator implemented as a class that produces the same squares.

python
class SquareIterator:
    def __init__(self, n):
        self.n = n
        self.i = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.i < self.n:
            result = self.i * self.i
            self.i += 1
            return result
        else:
            raise StopIteration

for value in SquareIterator(5):
    print(value)
Output
0 1 4 9 16
🎯

When to Use Which

Choose generators when you want a simple, memory-efficient way to produce items one by one, especially for large or infinite sequences. They are perfect for pipelines and lazy evaluation without the overhead of storing all items.

Choose iterators when you need more control over the iteration process, such as resetting, complex state management, or when implementing custom iterable objects. Iterators are also useful when you want to integrate with Python's iteration protocols explicitly.

Key Takeaways

Generators are a simple way to create iterators using functions with yield for lazy evaluation.
Iterators are objects with __next__() and __iter__() methods that control iteration explicitly.
Generators use less memory by producing items on demand, ideal for large or infinite data.
Iterators offer more flexibility but require more code to implement and manage state.
Use generators for simple, memory-efficient loops; use iterators for custom or complex iteration.