Intuition The one core idea
Looping over anything in Python is a tiny contract : an object promises to hand you items one at a time, on demand , and to shout a special signal when it runs out. Master two method names (__iter__, __next__) and one signal (StopIteration) and you understand every for loop that has ever run.
Before you can read the parent note Iterators — `__iter__`, `__next__`, StopIteration , you must own every word and symbol it silently assumes. This page builds each one from zero, in an order where each idea rests on the one before it.
Definition Object and method
An object is a bundle: some data (values it remembers) plus behaviours (things it can do). A method is a behaviour written as a function that lives inside the object and is called with a dot: thing.do_something().
Picture a vending machine. The data is "how many cans are inside". The methods are "press button", "return coins". You never reach inside — you press buttons. Methods are those buttons.
Intuition Why the topic needs this
The whole iterator protocol is just "which buttons must an object have so that for can press them?" If you don't picture objects as button-boxes, __next__ looks like magic instead of a button.
Definition Dunder (double-underscore) method
A method whose name starts and ends with two underscores, like ==__iter__==, is a dunder ("double under") method. Python calls these automatically in response to syntax you write — you rarely call them by hand.
Read __next__ out loud as "dunder next". The underscores are Python's way of saying: "this is a hook the language itself will call for you."
You write
Python secretly calls
len(x)
x.__len__()
x + y
x.__add__(y)
iter(x)
x.__iter__()
next(x)
x.__next__()
Intuition Why the topic needs this
The parent note keeps saying "iter() calls obj.__iter__()". That sentence only makes sense once you know dunders are the machinery behind ordinary-looking syntax . See Dunder (magic) methods for the whole family.
self
Inside a method, ==self== is the name for "the very object this method belongs to." Writing self.current means "the current value stored on me ."
Picture the vending machine holding a little note that says "I have 4 cans". When a method reads self.current, it is reading its own note, not some other machine's.
Intuition Why the topic needs this
Iterators remember where they are between button presses. That memory lives on self. When __next__ does self.current -= 1, it is updating its own private counter so the next press gives the next item.
return and raise
==return value== hands a result back to the caller and ends the method normally.
==raise SomeError== does not hand back a value; it throws a signal that travels up until some code catches it, or the program stops.
Picture return as placing a candy in your friend's hand . Picture raise as ringing an alarm bell — nobody gets candy; instead everyone reacts to the bell.
Common mistake "Both stop the method, so they're the same."
Why it feels right: both end the method's current run. The difference: return None still succeeds and the loop happily continues, handing back None forever. raise StopIteration is a different channel — the loop is specifically listening for it to know to stop. This is exactly the parent note's "return instead of raise" mistake.
StopIteration
==StopIteration== is a built-in exception (a raisable signal) whose only job is to mean "there are no more items." It is not a bug or an error you did wrong — it is the agreed end-of-tape click.
Picture a cassette tape. Every press of next plays a note. When the tape runs out, pressing again makes a small click — that click is StopIteration. The listener hears the click and stops pressing.
Intuition Why the topic needs this
Without an agreed "I'm empty" signal, the for loop could never know when to stop. StopIteration is that universal signal. (Generators handle it specially — see StopIteration and PEP 479 .)
try / except
try :
risky() # attempt this
except SomeError:
handle() # run this ONLY if that signal was raised
==try marks code that might raise a signal; except== catches a specific signal and lets you respond calmly instead of crashing.
Picture a smoke detector wired to one action: if the alarm rings (except StopIteration), then quietly leave the room (break). No alarm → keep working.
Intuition Why the topic needs this
The parent note's "what for really compiles to" wraps next() in try/except StopIteration: break. That is literally "press the button; if you hear the click, walk away."
while True and break
==while True:== repeats its body forever .
==break== is the emergency exit: it jumps out of the loop right now .
Picture a person pressing the next button over and over (while True) until they hear the click, at which point they stop pressing and step away (break).
Intuition Why the topic needs this
A for loop is a while True that presses next forever and only breaks when it catches StopIteration. Understanding this pair demystifies the "syntactic sugar" the parent note reveals.
Now every symbol in the parent's core loop is defined. Read it again — nothing is magic:
Every word here is one of Sections 1–6. See for loops and comprehensions for how this same machinery powers comprehensions.
Definition Iterable and iterator
An ==iterable == is a bag of candy : it can produce a fresh dispenser whenever asked (its __iter__ makes a new iterator).
An ==iterator == is the dispenser itself : press next to pop the next candy; it remembers its own position.
Intuition Why keep them separate?
A bag can hand out many dispensers, each with its own position — so two nested loops over one list don't interfere. If the bag were the dispenser, one loop would empty it for everyone. This is the parent note's whole iterable ≠ iterator point. Related: Lazy evaluation and memory efficiency and Generators — yield, lazy evaluation .
Read it top-to-bottom: objects give us dunders and self; those give us iter/next; return vs raise gives us the StopIteration signal caught by try/except; together they define the protocol. For composing iterators safely, continue to itertools — islice, count, chain .
Cover each answer and test yourself. If any one is fuzzy, reread its section before the parent note.
What is a method , in one sentence? A function that lives inside an object and is called with a dot, like a button on a machine.
What does a name like __next__ (a "dunder") signal? It is a hook Python calls automatically in response to syntax such as next(x).
Inside a method, what does self refer to? The very object the method belongs to — where its remembered state lives.
Difference between return v and raise E? return hands a value back and succeeds; raise throws a signal up the call stack until something catches it.
What is StopIteration for ? It is the agreed exception meaning "no more items" — the end-of-tape click, not an error.
What does try: / except StopIteration: let a loop do? Attempt next(), and calmly stop (break) exactly when the empty signal is raised.
What does break do inside while True:? Immediately exits the otherwise-forever loop.
Iterable vs iterator, in the candy metaphor? Iterable = bag that hands out fresh dispensers; iterator = the dispenser itself that remembers its position.
Why must a list NOT be its own iterator? So each iter(list) gives an independent position, letting nested loops over the same list work.