Skip to content
Laviyx Learn

Try

Python course menu

Python Iterators: iter(), next() and the Iterator Protocol

Understand how Python loops really work: iterables vs iterators, iter() and next(), StopIteration, building your own iterator class with __iter__ and __next__, one-time iterators, and useful tools from itertools.

Advanced8 min readUpdated
On this page

Every for loop in Python relies on two simple ideas: iterables and iterators. Understanding them explains why you can loop over lists, strings, files and dictionaries in exactly the same way, and lets you make your own objects loopable.

Iterable vs iterator#

TermMeaningExamples
Iterableanything you can loop over; it can produce an iteratorlists, strings, tuples, dicts, sets, files, range
Iteratoran object that gives the next value each time you ask, and remembers its positionwhat iter() returns; generators; map, zip, enumerate objects

iter() and next()#

iter() gets an iterator from an iterable; next() asks it for the next value:

Python
nums = [10, 20, 30]
it = iter(nums)

print(next(it))
print(next(it))
print(next(it))
print(next(it))
Output
10
20
30
StopIteration

When there are no values left, the iterator raises StopIteration.

What a for loop really does#

This loop:

Python
for n in nums:
    print(n)

works roughly like this:

Python
it = iter(nums)
while True:
    try:
        n = next(it)
    except StopIteration:
        break
    print(n)

for calls iter() once, calls next() repeatedly, and stops quietly at StopIteration. Any object that supports this iterator protocol works in a for loop, in list(), sum(), zip(), unpacking, and more.

Iterators are used up#

An iterator remembers its position and does not rewind:

Python
it = iter([10, 20, 30])
for n in it:
    print(n)
print(list(it))
Output
10
20
30
[]

The second pass gets nothing. A list is different: each loop calls iter() again and gets a fresh iterator. The same applies to map, filter and zip objects, which are iterators:

Python
r = range(3)
print(list(r), list(r))      # range is an iterable: reusable

m = map(str, [1, 2, 3])
print(list(m), list(m))      # map is an iterator: one pass only
Output
[0, 1, 2] [0, 1, 2]
['1', '2', '3'] []

Building your own iterator#

A class becomes an iterator by defining two special methods:

  • __iter__ returns the iterator itself.
  • __next__ returns the next value, or raises StopIteration when finished.
Python
class Countdown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        value = self.current
        self.current -= 1
        return value

for n in Countdown(3):
    print(n)

print(list(Countdown(5)))
Output
3
2
1
[5, 4, 3, 2, 1]

Like all iterators, one Countdown object can be consumed only once:

Python
c = Countdown(2)
print(list(c), list(c))
Output
[2, 1] []

Writing iterator classes by hand is a bit verbose; generators do the same job in a few lines, and are what most Python code uses.

Infinite and lazy iterators#

Iterators produce values on demand (lazily), so they can even be infinite. The itertools module has many ready-made ones:

Python
import itertools

print(list(itertools.islice(itertools.count(10, 5), 4)))       # 10, 15, 20, ... (first 4)
print(list(itertools.chain([1, 2], (3, 4))))                     # join iterables
print(list(itertools.zip_longest("ab", "xyz", fillvalue="-")))  # zip without truncating

for combo in itertools.combinations(["A", "B", "C"], 2):
    print(combo)
Output
[10, 15, 20, 25]
[1, 2, 3, 4]
[('a', 'x'), ('b', 'y'), ('-', 'z')]
('A', 'B')
('A', 'C')
('B', 'C')

islice takes the first few values of an iterator, which is essential for infinite ones like count().

Common mistakes#

Practice#

Practice exercise

Write an iterator class EvenNumbers(limit) that produces 2, 4, 6, … up to and including limit. Print list(EvenNumbers(10)).

Show hint

Start a counter at 0 in __init__. In __next__, add 2 and raise StopIteration once it passes the limit.

Show solution
Python
class EvenNumbers:
    def __init__(self, limit):
        self.limit = limit
        self.n = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.n += 2
        if self.n > self.limit:
            raise StopIteration
        return self.n

print(list(EvenNumbers(10)))
Output
[2, 4, 6, 8, 10]

Key takeaway#

Finished this lesson?