← Back to Python Course | Chapter 11: Advanced Python | Lesson 2 of 12

Python Generators

A generator makes values one at a time only when asked, like a machine that bakes one cookie whenever you press a button. It saves memory because it does not make everything at once.
Syntax
python
def generator_name():
    yield value1
    yield value2

for item in generator_name():
    # use item

What is a Generator?

A generator function looks like an ordinary function but uses yield instead of return, and calling it doesn't run the function body immediately -- it returns a generator object that produces values one at a time only as they're requested.

Example: What is a Generator?

python
def my_gen():
    yield 1  # yield instead of return makes this a generator function
    yield 2

g = my_gen()
print(type(g))  # generator object, body hasn't run yet
print(next(g))  # runs up to the first yield

The yield Keyword

Each time yield executes, the function pauses exactly there, hands back the yielded value, and remembers its entire local state (variables, position in loops) -- the next call to next() resumes execution right after that yield rather than starting the function over.

Example: The yield Keyword

python
def counter():
    n = 1
    while True:
        yield n  # pauses here, remembering n
        n += 1

c = counter()
print(next(c))  # first call, prints 1
print(next(c))  # second call, resumes after yield and prints 2

Generator Expressions

A generator expression -- (x*2 for x in range(10)) -- creates a generator with syntax almost identical to a list comprehension, but using parentheses instead of square brackets, and without ever building the full list of results in memory.

Example: Generator Expressions

python
squares = (x * x for x in range(5))
print(list(squares))

Generator State and Lifecycle

When a generator function runs off the end of its body or hits a plain return statement, Python automatically raises StopIteration to signal there's nothing left to produce -- this is exactly the same signal a for loop watches for when iterating any iterator.

Example: Generator State and Lifecycle

python
def one_value():
    yield "only value"

g = one_value()
print(next(g))
try:
    next(g)  # generator body has finished
except StopIteration:
    print("Generator exhausted")

Performance Benefits

Because a generator computes and yields one value at a time instead of building an entire list upfront, it uses a fixed, small amount of memory regardless of how many values it ultimately produces -- ideal for streaming through datasets too large to fit comfortably in RAM.

Example: Performance Benefits

python
import sys
list_version = [x for x in range(1000)]  # builds the entire list upfront
gen_version = (x for x in range(1000))  # produces values lazily, one at a time
print(sys.getsizeof(list_version) > sys.getsizeof(gen_version))
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Looping over a generator twice and getting nothing the second time, because it is exhausted after one pass.
  2. Using return value where you meant yield value, so the function runs once instead of producing a sequence.
  3. Converting a large generator to a list with list(gen), which loads everything into memory and loses the benefit.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.