Python Iterator vs Generator: What Is the Difference?
__next__(), and a generator is a simpler way to create an iterator by writing a function that uses yield. Every generator is an iterator, but not every iterator is a generator.Both let you walk through values one at a time without holding everything in memory, and both can be used in a for loop. They differ in how you create them. To build an iterator yourself you write a class with __iter__() and __next__() and keep track of the state by hand. A generator function does the same job in a few lines: Python remembers where the function paused at each yield.
The background is covered in Python iterators and Python generators. Here we compare them directly so you can choose the right one.
Iterator vs generator compared
| Aspect | Iterator | Generator |
|---|---|---|
| What it is | Any object with __iter__() and __next__() | A special iterator made by a yield function or generator expression |
| How you create it | Write a class, or call iter(x) | def f(): yield ... or (x for x in data) |
| State handling | You store it in attributes | Python saves local variables automatically |
| Amount of code | More | Less |
| Is it an iterator? | Yes | Yes, always |
| Can be reused after it is exhausted? | No (it must be created again) | No (call the function again) |
| Typical use | Custom iteration protocol, wrapping resources | Lazy sequences, pipelines, large or infinite streams |
When to use an iterator class
Write a class-based iterator when you need extra behaviour beyond producing values: methods like reset(), several attributes you want to expose, or an object that must work with code expecting a specific type. It also makes sense when the iteration logic is complex and benefits from the structure of a class. Most day-to-day code does not need this. Note that a list or a string is iterable but not an iterator: iter(items) produces the iterator for it.
When to use a generator
Use a generator for almost every other case: reading a big file line by line, producing a long or infinite sequence, or building a pipeline where each step handles one item at a time. Because values are produced lazily, memory stays small, and sum(n * n for n in range(1_000_000)) never builds a million-item list. Related tools such as itertools work well with generators.
One-time use: iterators and generators get exhausted
Both are used up after one pass. When no values are left, next() raises StopIteration and a for loop simply stops. A second loop over the same generator produces nothing, so store the values in a list or create a new generator if you need to iterate again. See StopIteration for what that exception means.
Examples you can run
Press Run, then edit the code and run it again.
Getting an iterator from a list with iter() and next()
A list is iterable, not an iterator. iter() gives you the iterator, and next() pulls items one by one.
scores = [70, 85, 92]
it = iter(scores)
print(next(it))
print(next(it))
print(list(it))Expected output70
85
[92]
A class-based iterator
The class stores the current number by hand and raises StopIteration when finished.
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
print(list(Countdown(3)))Expected output[3, 2, 1]
The same thing as a generator function
Five lines shrink to three, and Python keeps the state for us.
def countdown(start):
while start > 0:
yield start
start -= 1
gen = countdown(3)
print(list(gen))
print(list(gen))Expected output[3, 2, 1]
[]
A generator expression is lazy
Nothing is computed until something asks for the values; sum() consumes them one at a time.
squares = (n * n for n in range(1, 5))
print(type(squares).__name__)
print(sum(squares))Expected outputgenerator
30
Common mistakes
Looping over an exhausted generator
✗ Wrong
gen = (n for n in range(3))
print(list(gen))
print(list(gen))✓ Right
def make():
return (n for n in range(3))
print(list(make()))
print(list(make()))Create the generator again, or store the values in a list if you need them more than once.
Calling next() on a list
✗ Wrong
items = [1, 2, 3]
print(next(items))✓ Right
items = [1, 2, 3]
it = iter(items)
print(next(it))A list is iterable but not an iterator. Wrap it with iter() first.
Calling next() past the end
✗ Wrong
it = iter([1])
next(it)
next(it)✓ Right
it = iter([1])
print(next(it, None))
print(next(it, None))Give next() a default value, or loop with for, which handles the end for you.
Using return value instead of yield
✗ Wrong
def numbers():
return 1
return 2
print(list(numbers()))✓ Right
def numbers():
yield 1
yield 2
print(list(numbers()))A function with return is not a generator. Use yield for each value.
Python Iterator vs Generator: What Is the Difference?: questions people ask
Is a generator an iterator in Python?
Yes. Every generator is an iterator because it implements __iter__() and __next__() for you. The reverse is not true: a class-based iterator is not a generator.
What is the difference between iterable and iterator?
An iterable can produce an iterator when you call iter() on it, like a list or string, while an iterator is the object that actually hands out items with next(). Iterables can usually be looped over many times; iterators only once.
Why use a generator instead of returning a list?
A generator creates values on demand, so it uses very little memory and can start producing results immediately, even for huge or infinite sequences. Return a list when you need indexing, len() or several passes.
Keep learning
Step-by-step lessons:
Python IteratorsPython Generators, Iterators and yield
Related:
Python StopIterationPython List ComprehensionsPython enumerate() FunctionPython zip() FunctionPython map() Function
More in concepts:
Python Function vs Method: What Is the Difference?Python Module vs Package: What Is the Difference?Python @staticmethod vs @classmethod: What Is the Difference? See all →