Python iterators

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.

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.