Script Valley
Python: Complete Language Course
Advanced Python PatternsLesson 6.2

Python generators — yield and send explained

yield keyword, generator function, generator object, send method, yield from, generator vs iterator, practical generator patterns

Generators

A generator function uses yield instead of return. Calling it returns a generator object. The body executes lazily — only advancing when next() is called.

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

gen = fibonacci()
for _ in range(8):
    print(next(gen), end=" ")  # 0 1 1 2 3 5 8 13

def squares(n):
    for i in range(n):
        yield i ** 2

print(list(squares(5)))  # [0, 1, 4, 9, 16]

yield from

def chain(*iterables):
    for it in iterables:
        yield from it   # delegates to sub-iterator

print(list(chain([1, 2], [3, 4], [5])))
# [1, 2, 3, 4, 5]

send()

def accumulator():
    total = 0
    while True:
        value = yield total
        total += value

acc = accumulator()
next(acc)         # prime the generator
print(acc.send(10))  # 10
print(acc.send(5))   # 15

Generators are the foundation of async Python. Understanding yield makes async/await conceptually straightforward.

Generators are one of Python's most elegant features. They let you write pipeline-style data processing that is both readable and memory-efficient. A generator pipeline — read → filter → transform → aggregate — processes one item at a time through all stages, never materialising the full intermediate dataset. This scales to arbitrarily large files. The yield from syntax simplifies delegation to sub-iterators and is also the foundation of coroutines. Python's async/await syntax is built on the same suspension mechanism as generators, so mastering generators gives you the conceptual foundation for asynchronous programming.

Up next

Python context managers — writing your own with statement

Sign in to track progress