โญ๏ธIterators: __iter__, __next__, iter(), next()LESSON

Iterators: iter, next, iter(), next()

Every time you write for x in something:, Python is using the iterator protocol under the hood. Understanding it lets you create objects that work seamlessly with for loops, comprehensions, zip(), map(), and every other iteration context in Python.

Iterable vs Iterator

These two terms are related but distinct:

  • An iterable is any object you can loop over. It has __iter__() that returns an iterator.
  • An iterator is the object that produces values one at a time. It has both __iter__() (returns self) and __next__() (returns the next value, or raises StopIteration when exhausted).

iter() and next() Built-ins

iter(obj) calls obj.__iter__() and returns the iterator. next(it) calls it.__next__().

How for Loops Use the Protocol

The for loop is syntactic sugar for the iterator protocol:

Python calls iter() on the object once, then calls next() repeatedly until StopIteration is raised. The exception is caught automatically โ€” you never see it.

Building a Custom Iterator

To make an iterator, implement both __iter__ and __next__:

Iterables That Create Fresh Iterators

Notice that Countdown is both an iterable and an iterator โ€” calling iter() on it returns itself. This means you can only iterate it once. Lists are different: each call to iter(list) creates a fresh, independent iterator:

To make a reusable iterable that creates fresh iterators, separate the iterable class from the iterator class:

Infinite Iterators

An iterator doesn't have to end โ€” it can yield values forever. Useful for sequences like natural numbers or repeating patterns:

itertools.islice to Limit Infinite Iterators

itertools.islice(it, n) lets you take just the first n items from any iterator โ€” essential for working with infinite ones:

Practical Example: File Iterator

A classic real-world iterator is reading a large file line by line โ€” you don't load the entire file into memory:

Quick Reference

ConceptMethod/FunctionPurpose
Make iterable__iter__(self)Return an iterator
Make iterator__next__(self)Return next value or raise StopIteration
Get iteratoriter(obj)Call obj.__iter__()
Get next valuenext(it)Call it.__next__()
Limit iteratoritertools.islice(it, n)Take first n items
Check exhaustednext(it, default)Return default instead of raising

Knowledge Check

What is the difference between an iterable and an iterator?

What does an iterator's `__iter__` method return?

What happens when you call `next()` on an exhausted iterator?