1.3.10Python Intermediate

Iterators — `__iter__`, `__next__`, StopIteration

1,894 words9 min readdifficulty · medium1 backlinks

WHY does this exist?

WHAT problem it solves: how can for x in something: work uniformly over lists, files, dictionaries, ranges, and your own objects, without for knowing their internals? Answer: they all agree to speak the same tiny iterator protocol.


The Protocol (first principles)

So: iterable = "I can give you a fresh tape player." Iterator = "I am the tape player; press my button."

Figure — Iterators — `__iter__`, `__next__`, StopIteration

HOW to build one from scratch


Iterable ≠ Iterator (the key separation)


Common Mistakes (Steel-manned)


The 80/20 core


Recall Feynman: explain to a 12-year-old

Imagine a Pez candy dispenser. You press the top (next) and one candy pops out. You keep pressing and eating. When it's empty, pressing makes a little click that means "all gone" (StopIteration) — that's how your friend (the for loop) knows to stop asking. The dispenser itself is the iterator. A bag of candy is like a list: it's not a dispenser, but you can always pull out a fresh dispenser from it whenever you want to share — that's what __iter__ does for a list: it hands you a new dispenser each time.


Connections

  • Generators — yield, lazy evaluation — generators auto-implement this protocol for you.
  • for loops and comprehensions — built on iter/next under the hood.
  • itertools — islice, count, chain — composable iterators, safe handling of infinite ones.
  • Lazy evaluation and memory efficiency — the WHY behind iterators.
  • Dunder (magic) methods__iter__/__next__ are part of this family.
  • StopIteration and PEP 479 — why generators must return, not raise.

Flashcards

What two methods define the iterator protocol?
__iter__ (returns the iterator) and __next__ (returns next item / raises StopIteration).
What does an iterator's __iter__ return?
self.
What is the difference between an iterable and an iterator?
An iterable has __iter__ returning an iterator; an iterator has __next__ and is consumed as you advance.
How does for x in obj work internally?
it = iter(obj); loop next(it) in a try, catch StopIteration to break.
How does an iterator signal it is exhausted?
It raises StopIteration.
What does next(it, default) do?
Returns default instead of raising StopIteration when exhausted.
Why are lists not their own iterators?
So each iter(list) gives an independent position, allowing nested/independent loops.
Why must __iter__ of a reusable iterable return a NEW iterator?
Otherwise shared state gets exhausted and re-looping yields nothing.
In a hand-written __next__, how do you stop iteration?
raise StopIteration (not return).
Inside a generator, how do you stop — and why not raise StopIteration?
Use return; since PEP 479 a leaked StopIteration becomes a RuntimeError.

Concept Map

problem

solved by

defines

defines

has __iter__ returns

has __next__ returns

__iter__ returns

when exhausted

sugar for

catches

means

implements

List stores all in memory

Need lazy on-demand values

Iterator protocol

Iterable

Iterator

Next item

itself

raise StopIteration

for x in obj

iter then next in loop

loop stops quietly

Countdown class

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, iterator ka matlab hai ek aisa object jiske paas sirf ek button hai: next. Jab bhi tum button dabaate ho (next(it)), tumhe agla element milta hai. Jab list khatam ho jaati hai, toh wo StopIteration raise karta hai — yeh "tape khatam" ka signal hai, error nahi. Jo for loop hum daily likhte hain, wo internally yahi karta hai: pehle iter(obj) se tape player nikalta hai, phir baar baar next() dabaata hai, aur jaise hi StopIteration aaya, chup-chaap break kar deta hai.

Important baat — iterable aur iterator alag cheez hain. List ek iterable hai, par khud iterator nahi. Har baar iter(list) ek naya iterator deta hai apni alag position ke saath. Isi wajah se tum nested loops same list par chala sakte ho bina position gadbad hue. Agar tum apni class banaate ho, toh __iter__ aur __next__ dono likhne padte hain; iterator ka __iter__ self return karta hai.

Yeh kyun important hai? Kyunki iterator lazy hota hai — ek time pe ek element banata hai, poori list memory mein store nahi karta. Isiliye infinite sequences (jaise saare even numbers) ya badi files ko handle karna possible hota hai. Bas yaad rakhna: hand-written __next__ mein rukna ho toh return mat karo, raise StopIteration karo — warna loop kabhi khatam nahi hoga. Aur agar object ek hi baar loop ho raha hai dobara nahi, toh samajh jao ki uski state consume ho gayi — reusable banane ke liye __iter__ se naya iterator return karwao.

Go deeper — visual, from zero

Test yourself — Python Intermediate

Connections