What is an Iterator?
An iterator is an object in Python that contains a sequence of elements and provides a mechanism to traverse through them one at a time. It implements two key methods:
- __iter__(): Returns the iterator object itself.
- __next__(): Returns the next element in the sequence and raises a StopIteration exception when no more elements are available.
Understanding Iteration Protocol
Python’s iteration protocol is a set of rules that govern how objects behave during iteration. It requires two main components:
- Iterable: An object that can return an iterator using its __iter__() method. Examples include lists, tuples, and strings.
- Iterator: An object that represents a stream of data and provides the __next__() method to access each element in sequence.
Iterators vs. Iterables
Feature | Iterator | Iterable |
---|---|---|
Definition | Implements __iter__() and __next__() methods. | Implements __iter__() method. |
Usage | Used to fetch data sequentially. | Used to create an iterator. |
Examples | Objects created using iter(). | Lists, tuples, strings, etc. |
Examples of Iterators
Using an Iterator on a List
my_list = [1, 2, 3, 4]
my_iter = iter(my_list) # Create an iterator from the list
print(next(my_iter)) # Output: 1
print(next(my_iter)) # Output: 2
print(next(my_iter)) # Output: 3
print(next(my_iter)) # Output: 4
Here, iter() converts the list into an iterator and next() fetches the next element.
Manually Creating an Iterator
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:
result = self.current
self.current += 1
return result
else:
raise StopIteration
# Using the Counter iterator
counter = Counter(1, 5)
for num in counter:
print(num)
# Output:
# 1
# 2
# 3
# 4
# 5
Iterators in Loops
In Python, for loops work internally by creating an iterator from the iterable and calling the __next__() method in each iteration.
Example: For Loop with Iterators
my_tuple = (10, 20, 30)
for item in my_tuple:
print(item)
# Output:
# 10
# 20
# 30
The for loop automates the process of calling __iter__() and __next__().
Infinite Iterators
Python’s itertools module provides tools to create iterators with special functionalities, including infinite iterators.
Example: Infinite Counter
from itertools import count
for num in count(1):
if num > 5:
break
print(num)
# Output:
# 1
# 2
# 3
# 4
# 5
Advantages of Using Iterators
- Memory Efficiency: Iterators fetch data one element at a time, reducing memory usage.
- Lazy Evaluation: Elements are computed only when needed.
- Flexibility: Iterate over various data types seamlessly.
Common Pitfalls with Iterators
Exhaustion: An iterator gets exhausted once all elements are retrieved. You need to recreate it to iterate again.
my_iter = iter([1, 2, 3])
for item in my_iter:
print(item) # Works
for item in my_iter:
print(item) # No output; iterator is exhausted
StopIteration Exception: Raised if next() is called on an exhausted iterator.
Iterators vs. Generators
Feature | Iterator | Generator |
---|---|---|
Memory Usage | Stores entire sequence. | Yields elements one at a time. |
Creation | Explicitly defined with a class. | Created using yield in a function. |
Syntax | Implements __iter__() and __next__(). | Uses the yield keyword. |