Python > Advanced Python Concepts > Iterators and Generators > Creating Custom Iterators
Custom Iterator for Fibonacci Sequence
This example demonstrates how to create a custom iterator in Python to generate the Fibonacci sequence. Custom iterators provide fine-grained control over how data is produced, allowing for efficient and memory-friendly sequence generation.
Code Implementation
This code defines a class FibonacciIterator
that generates Fibonacci numbers up to a specified limit. The __init__
method initializes the starting values and the limit. The __iter__
method returns the iterator object itself. The __next__
method calculates the next Fibonacci number and returns it. When the limit is reached, it raises StopIteration
to signal the end of the sequence.
class FibonacciIterator:
def __init__(self, limit):
self.limit = limit
self.a = 0
self.b = 1
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.count < self.limit:
self.count += 1
fib_number = self.a
self.a, self.b = self.b, self.a + self.b
return fib_number
else:
raise StopIteration
# Example Usage:
fib_iter = FibonacciIterator(10)
for num in fib_iter:
print(num)
Concepts Behind the Snippet
Iterators are objects that allow you to traverse through a collection of data. To create a custom iterator in Python, you need to define a class with two essential methods: __iter__()
and __next__()
. __iter__()
should return the iterator object itself. __next__()
should return the next item in the sequence and raise StopIteration
when there are no more items.
Real-Life Use Case
Custom iterators are useful when dealing with large datasets or infinite sequences. For example, you can create an iterator to read data from a very large file chunk by chunk, processing each chunk as it is read, without loading the entire file into memory. They are also applicable when generating mathematical sequences like prime numbers or Fibonacci numbers where you want to compute values on demand.
Best Practices
__next__()
method correctly raises StopIteration
when the sequence is exhausted to prevent infinite loops.reset()
method to allow the iterator to be reused.
Interview Tip
Be prepared to explain the difference between iterators and iterables. An iterable is an object that can be iterated over (e.g., a list), while an iterator is an object that actually performs the iteration. You should also be able to explain the role of the __iter__()
and __next__()
methods.
When to Use Them
Use custom iterators when you need to generate a sequence of values on demand, especially when the sequence is very large or infinite. They are also appropriate when you need fine-grained control over the iteration process.
Memory Footprint
Iterators are memory-efficient because they generate values one at a time, rather than storing the entire sequence in memory. This is especially important when dealing with large datasets.
Alternatives
Generators, created using the yield
keyword, provide a more concise way to create iterators in many cases. List comprehensions and generator expressions can also be used for simple sequence generation, but they might not be as flexible as custom iterators for complex scenarios.
Pros
Cons
StopIteration
exception.
FAQ
-
What is the difference between an iterator and an iterable?
An iterable is an object that can be iterated over (e.g., a list, tuple, or string). An iterator is an object that performs the iteration, providing access to the elements of the iterable one at a time. An iterable has an__iter__()
method that returns an iterator. -
Why do I need to raise StopIteration?
StopIteration
is raised to signal that the iterator has reached the end of the sequence and there are no more elements to return. Without it, the iterator would continue to run indefinitely. -
Can I reset an iterator?
By default, iterators cannot be reset. Once they have reached the end of the sequence, they cannot be restarted. However, you can implement areset()
method in your custom iterator class to allow it to be reused.