Both generators and iterators are used to iterate over data in Python, but they differ in how they are implemented and used.
| Feature | Iterator | Generator |
|---|---|---|
| Definition | An object that implements the __iter__() and __next__() methods. | A special type of iterator created using a function with yield or generator expression. |
| Creation | Created using classes or the iter() function. | Created automatically using a yield statement inside a function. |
| Memory Usage | Can be memory-heavy if it stores large data. | Memory-efficient — generates items on the fly. |
| Return Type | Returns data using the return statement. | Returns data using the yield keyword. |
| Syntax Simplicity | More complex (requires class implementation). | Easier and cleaner to implement. |
| Reusability | Once exhausted, needs to be recreated manually. | Once exhausted, also needs to be recreated. |
🧩 Example 1: Iterator
# Creating an iterator using a class
class Counter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def __next__(self):
if self.current > self.high:
raise StopIteration
else:
num = self.current
self.current += 1
return num
counter = Counter(1, 5)
for num in counter:
print(num)Output:
1
2
3
4
5🧩 Example 2: Generator
# Creating a generator using yield
def counter(low, high):
while low <= high:
yield low
low += 1
for num in counter(1, 5):
print(num)Output:
1
2
3
4
5🧩 Example 3: Generator Expression (Compact Form)
squares = (x*x for x in range(5))
print(next(squares))
print(next(squares))Output:
0
1In Summary:
- Iterators are objects following the iterator protocol (
__iter__()and__next__()). - Generators are a simpler way to create iterators using
yield. - Generators are more memory-efficient and easier to implement than custom iterators.
