datarekha
Python Medium Asked at AmazonAsked at MicrosoftAsked at Meta

What is the difference between an iterable and an iterator in Python?

The short answer

An iterable implements __iter__ and returns an iterator. An iterator implements both __iter__ (returning itself) and __next__ (producing the next value or raising StopIteration). Every iterator is an iterable, but not every iterable is an iterator.

How to think about it

What the interviewer is really checking

This question separates candidates who memorised “for loops work on lists” from those who understand the protocol that makes Python’s for loop, zip, map, and comprehensions all work the same way. The answer hinges on two dunder methods.

The two-method protocol

The iterator protocol is exactly two dunder methods:

Object__iter____next__
Iterablereturns an iteratornot required
Iteratorreturns selfproduces next value or raises StopIteration

When Python executes for x in obj, it calls iter(obj) to get an iterator, then repeatedly calls next() on it until StopIteration is raised. That’s the entire mechanism.

Working through it step by step

A list is an iterable — it knows how to produce an iterator when asked, but it is not itself an iterator. Calling iter() on it returns a separate list_iterator object that tracks position:

nums = [1, 2, 3]
it = iter(nums)           # creates a list_iterator — different object
print(next(it))           # 1
print(next(it))           # 2
print(next(it))           # 3
# next(it) now → StopIteration

A generator expression is already an iterator — calling iter() on it returns itself:

gen = (x**2 for x in range(3))
print(iter(gen) is gen)   # True  — __iter__ returns self

Interactive demo — see the protocol in action

The key insight — single-pass vs multi-pass

The separation of iterable and iterator solves an important design problem: you can iterate the same list multiple times because each call to iter() creates a fresh iterator starting from the beginning. If the list itself were the iterator, it could only be consumed once.

Generators and file objects are single-pass iterators — once exhausted, they are gone. This is intentional for memory efficiency but is the source of a common bug.

Learn it properly Iterators

Keep practising

All Python questions

Explore further

Skip to content