Iterators: __iter__ & __next__
The iterator protocol is the simple contract behind every Python loop: an iterable returns an iterator from its __iter__ method, and that iterator hands back one value per call to __next__ until it raises StopIteration to signal the end.
Learn Iterators: __iter__ & __next__ in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Understanding this protocol demystifies the for-loop, generators, and half the standard library — and lets you build your own loopable objects.
Call iter() on any iterable to get an iterator, then call next() to pull values one at a time. When the items run out, next() raises StopIteration :
To make your own loopable object, implement two dunder methods: __iter__ returns the iterator (usually self ), and __next__ returns the next value or raises StopIteration :
Because the class implements the protocol, every Python construct that loops — for , list() , sum() , comprehensions, unpacking — works on it automatically. That's the power of following the protocol.
A generator function with yield produces an iterator for free — Python writes __iter__ and __next__ behind the scenes. Compare the same countdown both ways:
Replace each ___ so the class is a valid iterator that yields 1, 2, 3 then stops.
Build an iterator that yields the first n Fibonacci numbers using the protocol — a classic that shows off lazy, stateful iteration.
Lesson complete — the for-loop holds no secrets!
You can tell an iterable from an iterator, drive iteration with iter() and next() , handle StopIteration , write a custom iterator class with __iter__ and __next__ , and you know when a generator is the simpler choice.
🚀 Up next: Checkpoint — Data Structures — put it all together in a build challenge.
Practice quiz
What is the difference between an iterable and an iterator?
- They are identical
- An iterator is always a list
- An iterable produces an iterator; an iterator walks through items via __next__
- An iterable has no __iter__
Answer: An iterable produces an iterator; an iterator walks through items via __next__. An iterable returns an iterator from __iter__; the iterator yields items one at a time via __next__.
Which two dunder methods make up the iterator protocol?
- __iter__ and __next__
- __init__ and __call__
- __get__ and __set__
- __enter__ and __exit__
Answer: __iter__ and __next__. An iterator implements __iter__ (returns itself) and __next__ (returns the next value).
What does an iterator's __next__ do when there are no items left?
- Returns None
- Returns 0
- Loops forever
- Raises StopIteration
Answer: Raises StopIteration. __next__ raises StopIteration to signal the end of iteration.
How does a for-loop end when looping over an iterator?
- It counts the length first
- It catches StopIteration and stops
- It checks for None
- It runs a fixed number of times
Answer: It catches StopIteration and stops. The for-loop repeatedly calls next() and stops when StopIteration is raised.
Given an exhausted iterator it, what does next(it, 'DONE') return?
- 'DONE'
- StopIteration
- None
- An error
Answer: 'DONE'. next() with a default returns that default instead of raising StopIteration.
After it = iter([1, 2]); list(it), what does a second list(it) give?
An iterator is one-shot; once exhausted it yields nothing, so the second list() is empty.
For the Fibonacci iterator in the lesson, what does list(Fib(10)) produce?
Starting from a=0, b=1, the first 10 Fibonacci numbers are [0, 1, 1, 2, 3, 5, 8, 13, 21, 34].
What should __iter__ return to satisfy the protocol?
- A list
- None
- A string
- Something with a __next__ method (often self)
Answer: Something with a __next__ method (often self). Returning a non-iterator (like a list) causes TypeError: iter() returned non-iterator; return self or iter(...).
Why is a generator function (using yield) often simpler than a full iterator class?
- It runs faster always
- Python writes __iter__ and __next__ for you
- It needs no StopIteration ever
- It cannot be exhausted
Answer: Python writes __iter__ and __next__ for you. A generator gives you the __iter__/__next__ machinery automatically.
What does list(CountDown(4)) produce for the lesson's CountDown iterator?
CountDown(4) yields 4, 3, 2, 1 before raising StopIteration.