In Python, iterators are objects that allow you to traverse through all the elements of a collection (such as lists, tuples, or dictionaries) one at a time. Iterators are a key part of Python’s data-handling capabilities, enabling efficient processing of data structures or even creating custom iteration logic.
The function returns an iterator object that defines the method next(), which accesses elements in the container one at a time.
When there are no more elements, next() raises a StopIteration exception, which tells the for loop to terminate.
Key Concepts of Iterators
Iterator Protocol: An object is considered an iterator if it implements two special methods:
- __iter__() – Returns the iterator object itself and is used for initialization.
- __next__() – Returns the next item in the sequence and raises StopIteration when there are no more items.
Iterable vs. Iterator:
Iterable: An object that can return an iterator, typically using the __iter__() method (e.g., lists, tuples, dictionaries).
Iterator: An object that keeps track of its current state and knows how to fetch the next element in the sequence. It is created by calling iter() on an iterable.
Example:
Consider a list, which is an iterable. You can get an iterator from it using the iter() function:
# List (Iterable)
numbers = [1, 2, 3]
# Getting an Iterator
iterator = iter(numbers)
# Using the Iterator
print(next(iterator)) # Output: 1
print(next(iterator)) # Output: 2
print(next(iterator)) # Output: 3
If you call next(iterator) after the last item, it will raise a StopIteration exception, signaling that the iteration is complete.
Creating a Custom Iterator
To create a custom iterator, you define a class with __iter__() and __next__() methods.
Here’s an example of a custom iterator that generates a sequence of numbers up to a specified limit:
class MyIterator:
def __init__(self, max_value):
self.max_value = max_value
self.current = 0
def __iter__(self):
return self # An iterator returns itself
def __next__(self):
if self.current < self.max_value:
result = self.current
self.current += 1
return result
else:
raise StopIteration
# Using the custom iterator
iterator = MyIterator(5)
for number in iterator:
print(number) # Output: 0 1 2 3 4
In this example:
The __iter__() method returns the iterator instance itself.
The __next__() method increments the current attribute until it reaches max_value, after which it raises StopIteration
Difference between Iterators vs Generators
While iterators and generators both allow you to iterate through data, they are slightly different:
Iterators require you to implement __iter__() and __next__().
Generators simplify iteration by using the yield keyword, automatically managing the state without needing to write __iter__() and __next__() methods.