All Courses
Advanced Python

Python Generators

What is a Generator?

A generator is a special type of iterator — created using a function with the yield keyword instead of return. It was introduced to make creating iterators simpler and more memory-efficient.

Iterator (legacy) Generator
Created with A class with __iter__ and __next__ A function with yield
next() support
StopIteration Must raise manually Raised automatically
Complexity More boilerplate Much simpler

The yield Keyword

  • Like return, it sends a value back to the caller
  • Unlike return, it pauses the function and preserves its internal state
  • When next() is called again, execution resumes from where it left off
def gen():
    yield 1
    yield 2
    yield 3

itr = gen()             # returns a generator object (not the result)

print(type(gen))        # <class 'function'>
print(type(itr))        # <class 'generator'>

print(next(itr))        # 1
print(next(itr))        # 2
print(next(itr))        # 3
print(next(itr))        # ❌ StopIteration

Execution flow: 1. First next() → runs until yield 1, pauses, returns 1 2. Second next() → resumes, runs until yield 2, pauses, returns 2 3. Third next() → resumes, runs until yield 3, pauses, returns 3 4. Fourth next() → no more yield → raises StopIteration


Looping Through a Generator

Since a generator is an iterator, you can use it in a for loop:

for i in gen():
    print(i)   # 1  2  3

Practical Example — Fibonacci Sequence

Traditional approach (stores everything in a list ⚠️)

fib_numbers = [1, 1]
for i in range(2, 10):
    last = fib_numbers[i - 1]
    second_last = fib_numbers[i - 2]
    fib_numbers.append(last + second_last)

print(fib_numbers)

Problem: stores every number in memory. For 10 million terms, the list becomes huge.

Generator approach (stores only what's needed ✅)

def fib(n):
    last = 1
    second_last = 1
    current = 3          # first two terms (1, 1) are already known

    while current <= n:
        num = last + second_last
        yield num
        second_last = last
        last = num
        current += 1

for val in fib(10):
    print(val)   # 2 3 5 8 13 21 34 ...

Only two variables (last, second_last) are stored at any time — not the whole sequence.

Step-by-step for the first two iterations:

Step last second_last num yielded
current=3 1 1 2
current=4 2 1 3
current=5 3 2 5

Why Use a Generator?

Use a generator when Use a list when
You only need one value at a time You need random access to any value
The sequence is infinite or very large The sequence is small and finite
Memory efficiency matters You need all values available simultaneously
Values are generated on demand All values are needed at once

Key insight: A generator doesn't store the whole sequence — it computes the next value on demand. This makes it ideal for infinite or very large sequences.


Key Takeaways & Recap

Concept Summary
Generator A function with yield — returns a generator object when called
yield Pauses execution and returns a value; resumes on next next() call
StopIteration Raised automatically when the generator is exhausted
Memory efficient Only current state is stored — not all values
Iterable Can be used in for loops just like any iterator
When to use Infinite sequences, large datasets, one-value-at-a-time access