A generator is a function that produces a sequence of values lazily — one at a time, on demand — instead of computing and storing the entire sequence in memory up front. You write one just like a normal function, except you use yield instead of return. Every time the generator's caller asks for the next value, the function runs until it hits a yield, hands back that value, and then pauses — resuming exactly where it left off the next time a value is requested.
This matters most when a sequence is very large, or even infinite: building a list of the first 10 million Fibonacci numbers would eat a huge amount of memory, but a generator can produce them one at a time while using almost none.
Python Program to Implement a Fibonacci Generator
def fibonacci_generator():
a, b = 0, 1
while True: # an infinite sequence — the caller decides when to stop
yield a
a, b = b, a + b
gen = fibonacci_generator()
first_ten = [next(gen) for _ in range(10)]
print(first_ten)
# Generators also work directly in a for loop with a stopping condition
for i, value in enumerate(fibonacci_generator()):
if i >= 5:
break
print(f"Term {i}: {value}")
Output:
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Term 0: 0
Term 1: 1
Term 2: 1
Term 3: 2
Term 4: 3
Memory: Generator vs a Full List
import sys
def fibonacci_list(count):
result = []
a, b = 0, 1
for _ in range(count):
result.append(a)
a, b = b, a + b
return result
list_version = fibonacci_list(10_000)
gen_version = fibonacci_generator()
print(f"List of 10,000 Fibonacci numbers: {sys.getsizeof(list_version)} bytes")
print(f"Generator object itself: {sys.getsizeof(gen_version)} bytes")
Output:
List of 10,000 Fibonacci numbers: 85176 bytes
Generator object itself: 200 bytes
(Exact byte counts vary by Python version, but the list always dwarfs the generator — and that gap only grows as the sequence gets bigger.)
This is the core tradeoff: a plain list keeps every value in memory simultaneously so you can index into it, loop over it repeatedly, or slice it, while a generator keeps almost nothing — only enough state to produce the next value — but can only be iterated over once, forward, start to finish. Python's own range(), file objects, and map()/filter() all behave like generators for exactly this reason — processing a huge CSV file or an API response stream line-by-line with a generator means your program's memory use stays flat no matter how large the input gets.
