Generator vs Iterator in Python: Key Differences and Usage
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.
| Aspect | Generator | Iterator |
|---|---|---|
| Definition | A function or expression that yields items lazily using yield | An object with __next__() method that returns next item |
| Creation | Created by generator functions or generator expressions | Created by calling iter() on iterable or custom class with __iter__() and __next__() |
| Memory Usage | Low memory, produces items on demand | Depends on implementation; can store entire data or produce on demand |
| Syntax | Uses yield keyword | Implements __next__() and __iter__() methods |
| Reusability | Single-use; exhausted after iteration | Can be designed reusable or single-use depending on implementation |
| Use Case | Efficient looping over large or infinite sequences | General 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.
def square_generator(n): for i in range(n): yield i * i for value in square_generator(5): print(value)
Iterator Equivalent
This is the equivalent iterator implemented as a class that produces the same squares.
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)
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.