0Pricing
Python Academy · Lesson

The Iterator Protocol

Understand __iter__ and __next__.

The Iterator Protocol is a free Python Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Iteration?

Whenever you write a for loop over a list, string, or dict, Python is using the iterator protocol behind the scenes.

An object you can loop over is called an iterable. The thing that actually produces values one at a time is called an iterator.

for ch in 'abc':
    print(ch)

iter() and next()

Two built-in functions drive iteration:

  • iter(obj) asks an iterable for its iterator.
  • next(it) asks the iterator for the next value.

When there are no more values, next() raises StopIteration.

it = iter([10, 20, 30])
print(next(it))
print(next(it))
print(next(it))

StopIteration

Calling next() one time too many raises StopIteration. A for loop catches this automatically and stops cleanly.

it = iter([1])
print(next(it))
try:
    next(it)
except StopIteration:
    print('No more items')

The Two Dunder Methods

To make your own iterator you implement two methods:

  • __iter__ returns the iterator object itself.
  • __next__ returns the next value or raises StopIteration.
class Count:
    def __init__(self, n):
        self.i = 0
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= self.n:
            raise StopIteration
        self.i += 1
        return self.i

for x in Count(3):
    print(x)

Iterable vs Iterator

An iterable only needs __iter__. An iterator needs both __iter__ and __next__.

Lists are iterable but not iterators: each call to iter() gives a fresh iterator.

nums = [1, 2, 3]
print(iter(nums) is iter(nums))
it = iter(nums)
print(it is iter(it))

Iterators Are Exhausted Once

An iterator can be consumed only once. After you reach the end, it stays empty. To loop again, create a new iterator.

it = iter([1, 2])
print(list(it))
print(list(it))

A Range-Like Iterator

Let's build a custom iterator that behaves like a simple counter. Notice how state lives in the instance.

class EvenUpTo:
    def __init__(self, limit):
        self.cur = 0
        self.limit = limit
    def __iter__(self):
        return self
    def __next__(self):
        if self.cur > self.limit:
            raise StopIteration
        value = self.cur
        self.cur += 2
        return value

print(list(EvenUpTo(8)))

Separating Iterable and Iterator

A cleaner design keeps the container and the iterator separate, so the container can be looped many times.

class Bag:
    def __init__(self, items):
        self.items = items
    def __iter__(self):
        return BagIterator(self.items)

class BagIterator:
    def __init__(self, items):
        self.items = items
        self.i = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= len(self.items):
            raise StopIteration
        v = self.items[self.i]
        self.i += 1
        return v

b = Bag(['x', 'y'])
print(list(b))
print(list(b))

Using next() With a Default

next(it, default) returns the default instead of raising StopIteration when the iterator is empty. Handy for safe peeking.

it = iter([42])
print(next(it, 'done'))
print(next(it, 'done'))

Iterators Are Memory Friendly

Iterators yield one item at a time, so they do not need to hold the whole sequence in memory. This is why they scale to huge or even infinite streams.

class Naturals:
    def __init__(self):
        self.n = 0
    def __iter__(self):
        return self
    def __next__(self):
        self.n += 1
        return self.n

it = iter(Naturals())
print(next(it), next(it), next(it))

Built-ins That Consume Iterators

Many built-ins accept any iterator: sum, max, min, sorted, list, tuple. They pull values until StopIteration.

class Count:
    def __init__(self, n):
        self.i = 0
        self.n = n
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= self.n:
            raise StopIteration
        self.i += 1
        return self.i

print(sum(Count(5)))
print(max(Count(5)))

Quick Check

Test your understanding of the iterator protocol.

Recap

You learned the iterator protocol:

  • iter() gets an iterator; next() pulls values.
  • StopIteration signals the end and for handles it.
  • Custom iterators implement __iter__ and __next__.
  • Iterators are single-use and memory friendly.

Next you'll let Python write iterators for you with yield.

Frequently asked questions

Is the “The Iterator Protocol” lesson free?

Yes — the full text of “The Iterator Protocol” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.

What will I learn in “The Iterator Protocol”?

Understand __iter__ and __next__. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Python Academy?

No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “The Iterator Protocol” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Python Academy lesson?

Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Iterator Protocol
  2. Generator Functions
  3. Generator Expressions
  4. yield from and Delegation
← Back to Python Academy