__iter__
__iter__(self) __iter__ is called whenever Python needs to iterate over an object. It returns an iterator — typically self, but potentially any object with a __next__ method. Without __iter__, Python falls back to __getitem__ if available, using sequential integer indices until an IndexError.
Signature
def __iter__(self):
return self # most common: object is its own iterator
__iter__ takes only self. It should return an iterator object. The returned object is what for loops, list(), set(), and other iteration consumers actually iterate over.
Quick example
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)
# Output: 3
# Output: 2
# Output: 1
# Output: 0
The for loop calls iter(Countdown(3)), which calls Countdown(3).__iter__(). That returns self, so the loop then calls __next__ on the same object until it raises StopIteration.
Iterable vs iterator
These two terms mean different things:
- Iterable: an object with
__iter__. You can calliter()on it. - Iterator: an object with both
__iter__and__next__. It produces items one at a time.
Many objects are both at once — they implement __iter__ returning self and __next__ producing items. But you can also split the roles:
class Book:
def __init__(self, pages):
self.pages = pages
def __iter__(self):
return PageIterator(self.pages)
class PageIterator:
def __init__(self, pages):
self.pages = pages
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.pages):
raise StopIteration
page = self.pages[self.index]
self.index += 1
return page
book = Book(["page 1", "page 2", "page 3"])
for page in book:
print(page)
# page 1
# page 2
# page 3
The Book is an iterable — it has __iter__ but returns a separate PageIterator. The PageIterator is the actual iterator, maintaining state across calls to __next__.
Patterns
Return self for a self-iterating object
The most common pattern. The object is both iterable and iterator:
class Repeater:
def __init__(self, value, times):
self.value = value
self.times = times
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.count >= self.times:
raise StopIteration
self.count += 1
return self.value
for word in Repeater("hi", 3):
print(word)
# hi
# hi
# hi
Delegate to an internal sequence
When you already have an iterable backing your class:
class Stack:
def __init__(self):
self._items = []
def push(self, item):
self._items.append(item)
def __iter__(self):
return iter(self._items) # delegate to list's iterator
stack = Stack()
stack.push("a")
stack.push("b")
stack.push("c")
for item in stack:
print(item)
# a
# b
# c
This is cleaner than manually implementing __next__ — you get iteration for free.
Return a fresh iterator each time
Returning a new iterator object lets you iterate the same collection multiple times simultaneously:
class Grid:
def __init__(self, rows, cols):
self.rows = rows
self.cols = cols
def __iter__(self):
return GridIterator(self.rows, self.cols)
class GridIterator:
def __init__(self, rows, cols):
self.r = 0
self.c = 0
self.rows = rows
self.cols = cols
def __iter__(self):
return self
def __next__(self):
if self.r >= self.rows:
raise StopIteration
value = (self.r, self.c)
self.c += 1
if self.c >= self.cols:
self.c = 0
self.r += 1
return value
g = Grid(2, 3)
for cell in g:
print(cell)
# (0, 0)
# (0, 1)
# (0, 2)
# (1, 0)
# (1, 1)
# (1, 2)
Where iter gets called
A surprising number of Python constructs call __iter__ indirectly:
| Expression | How it reaches __iter__ |
|---|---|
for x in obj | iter(obj) → obj.__iter__() |
list(obj) | iter(obj) → obj.__iter__() |
tuple(obj) | iter(obj) → obj.__iter__() |
set(obj) | iter(obj) → obj.__iter__() |
any(obj), all(obj) | iter(obj) → obj.__iter__() |
max(obj), min(obj) | iter(obj) → obj.__iter__() |
sorted(obj) | iter(obj) → obj.__iter__() |
enumerate(obj) | iter(obj) → obj.__iter__() |
zip(a, b) | iter(a) and iter(b) |
Gotchas
getitem fallback
If an object has no __iter__ but does have __getitem__, Python will iterate using integer indices starting at 0 until IndexError. This is how plain list-like objects worked before the iterator protocol existed:
class OldSchoolSequence:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
# This actually works — __iter__ is not needed
for item in OldSchoolSequence([1, 2, 3]):
print(item)
# 1
# 2
# 3
If both __iter__ and __getitem__ exist, Python uses __iter__ only.
Non-iterator return type
If __iter__ returns an object without __next__, Python raises TypeError when iteration is attempted:
class BadIterable:
def __iter__(self):
return "not an iterator" # string has no __next__
for x in BadIterable():
print(x)
# TypeError: 'str' object is not an iterator
Iterators are one-shot
An iterator that returns self from __iter__ is consumed after one pass. The same object reference is exhausted:
counter = Countdown(3)
print(list(counter)) # [3, 2, 1, 0]
print(list(counter)) # [] — already exhausted
If you need reusable iteration, return a fresh iterator from __iter__.
Generators have iter automatically
Generator functions (def ... yield) and generator expressions create objects that already implement __iter__ and __next__ — you don’t need to define either manually:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
fib = fibonacci(5)
for num in fib:
print(num)
# 0
# 1
# 1
# 2
# 3
See Also
- next() — retrieve the next item from an iterator
- iter() — obtain an iterator from an iterable
- next — produce the next item in an iterator
- Understanding Generators — how generators fit into the iteration protocol