Iterators and generators are key tools in Python that enable efficient iteration over data.
An iterator is an object that can be iterated upon, meaning you can traverse through all the values. It implements two special methods:
__iter__()
: Returns the iterator object itself.__next__()
: Returns the next value and raises StopIteration
when there are no more items.# Creating an iterator from a list
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator)) # Output: 1
print(next(iterator)) # Output: 2
print(next(iterator)) # Output: 3
If you call next()
on an iterator after it is exhausted, it raises a StopIteration
exception.
You can create a custom iterator by defining a class with __iter__()
and __next__()
methods.
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
else:
self.current += 1
return self.current - 1
counter = Counter(1, 5)
for num in counter:
print(num)
A generator is a simpler way to create iterators. Instead of using __iter__()
and __next__()
, you define a function and use the yield
keyword to yield values one at a time.
# A simple generator
def my_generator():
yield 1
yield 2
yield 3
for value in my_generator():
print(value)
Generators can also be created using a generator expression, similar to list comprehensions but with parentheses.
squares = (x**2 for x in range(5))
for square in squares:
print(square)
Generators are memory-efficient because they yield values one at a time instead of storing all values in memory.
Feature | Iterator | Generator |
---|---|---|
Creation | Requires __iter__ and __next__ methods | Defined using a function and yield keyword |
Memory Usage | Can store all data in memory | Yields one item at a time (lazy evaluation) |
Complexity | More complex to implement | Simpler and more concise |
Custom Iterator:
Example:
class EvenNumbers:
def __init__(self, max):
self.current = 0
self.max = max
def __iter__(self):
return self
def __next__(self):
if self.current > self.max:
raise StopIteration
else:
self.current += 2
return self.current - 2
for num in EvenNumbers(10):
print(num)
Simple Generator:
Example:
def squares(limit):
for i in range(limit):
yield i**2
for square in squares(5):
print(square)
Generator Expression:
Example:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for fib in fibonacci(10):
print(fib)