PyComplete Python Course
Advanced 35 min

Module 13 β€” Generators

Producing values one at a time, on demand, instead of all at once.

Prerequisite: Module 12 β€” Closures & Decorators

After this lesson, you will be able to

  • Write a generator function using yield
  • Explain lazy evaluation and why it saves memory
  • Write a generator comprehension

Concept & Syntax

A normal function computes its entire result and returns it all at once. A generator function instead uses yield to hand back one value at a time, pausing itself exactly where it left off, and only resuming when the next value is asked for. This is called lazy evaluation.

The payoff is memory. A list of one million numbers takes up space for all one million, all the time. A generator that yields one million numbers only ever holds one number in memory at any moment β€” hugely useful when working with large or even infinite sequences.

Syntax
def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1
 
for number in count_up_to(5):
    print(number)

Examples

A simple generator function Very Easy

A simple generator function
def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1
 
for number in count_up_to(5):
    print(number)
Output1 2 3 4 5

Each time the loop asks for the next value, the function resumes right after its last yield, runs a bit more, then pauses again.

Calling next() manually Intermediate

Calling next() manually
def two_numbers():
    yield 10
    yield 20
 
gen = two_numbers()
print(next(gen))
print(next(gen))
Output10 20

next() pulls the next yielded value out of the generator. Calling it a third time here would raise StopIteration.

Generator comprehension Real World

Generator comprehension
squares = (x * x for x in range(1000000))
print(next(squares))
print(next(squares))
Output0 1

Parentheses (instead of square brackets) create a generator comprehension β€” a million squares are never all stored in memory at once, only computed as needed.

Visual Explanation

Generator function called β†’ returns a generator object (nothing runs yet)next() called β†’ runs until the first yield, returns that value, then pausesnext() called again β†’ resumes right after the last yieldFunction runs off the end β†’ StopIteration is raised
A generator's execution pauses and resumes across multiple calls to next().
πŸ’‘ Why does this work?

Read the concept explanation above again slowly, line by line β€” every keyword there maps directly onto a line of code in the examples. If it still doesn't click, re-run the traced example (if this lesson has one) one step at a time.

πŸ” What happens internally? (advanced)

Under the hood, Python compiles your source into bytecode and runs it on a virtual machine (the CPython interpreter). Variables are names in a namespace dictionary pointing at objects in memory β€” which is exactly what the memory panel in the tracer above is showing you.

Common Mistakes

βœ— Common mistake 1

A function containing yield never runs its body immediately when called β€” calling it just creates a generator object.

βœ— Avoid this
This raises prints something like <generator object numbers at 0x...>, not 1 or 2
def numbers():
    yield 1
    yield 2
 
print(numbers())
βœ“ Better approach
Fixed
def numbers():
    yield 1
    yield 2
 
for n in numbers():
    print(n)
βœ“ Best practices
  • Use a generator instead of building a full list whenever you only need to iterate once, especially over large data.
  • Prefer a generator comprehension (x for x in ...) over a list comprehension when you don't need random access or len().
  • Remember a generator can only be iterated through once β€” once exhausted, you must create a new one.

Exercise & Challenge

Exercise 1 β€” Predict the output

Given this code
def letters():
    yield "a"
    yield "b"
 
g = letters()
next(g)
print(next(g))

What does this print?

πŸ† Challenge

Write a generator function even_numbers(limit) that yields even numbers from 0 up to (not including) limit, then use it in a for loop to print them.

  • Use yield, not return
  • Only yield even numbers
  • Stop before reaching limit
πŸ’‘ Need a hint?

A while loop with i += 2 naturally produces only even numbers if it starts at 0.

πŸ” Show a sample solution
Python
def even_numbers(limit):
    i = 0
    while i < limit:
        yield i
        i += 2
 
for n in even_numbers(10):
    print(n)

Quiz

Answer every question, then submit to see your score and explanations.

1. What keyword turns a regular function into a generator function?

return
yield
async
pause
yield is what makes a function a generator.

2. What happens when you call a generator function?

Its whole body runs immediately
It returns a generator object; nothing runs yet
It raises an error
It returns a list
Calling a generator function just creates the generator β€” execution starts on the first next() call.

3. Why are generators more memory-efficient than building a full list?

They compress data
They only hold one value in memory at a time, computing each on demand
They use a database
They aren't actually more efficient
Lazy evaluation means generators never store the whole sequence at once.

Summary

  • yield turns a function into a generator that produces values one at a time.
  • Calling a generator function doesn't run its body β€” only next() (or a for loop) does.
  • Generators use lazy evaluation, making them far more memory-efficient than full lists for large sequences.
  • A generator can only be consumed once.

Related lessons

Saved privately in your browser β€” no account needed.