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.