Welcome to part two of our Python 3 features series! Today, we’re unleashing the power of generators with yield from and checking out how they paved the way for coroutines.

Generators let you produce values on the fly using yield. But once you start nesting generators, boilerplate can pile up. That’s where yield from swoops in.

Quick Generator Recap

A simple generator:

def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1

for num in count_up_to(3):
    print(num)  # 1, 2, 3

Generators pause and resume, making them great for streaming data or lazy evaluation.

The Problem with Generator Delegation

Imagine one generator wants to hand off part of its job to another:

def generate_letters():
    for ch in 'abc':
        yield ch

def generate_all():
    yield 'start'
    for item in generate_letters():
        yield item  # tedious repetition
    yield 'end'

That loop is boring and easy to mess up.

Enter yield from

yield from <subgen> replaces the inner loop, forwarding values and even exceptions:

def generate_all():
    yield 'start'
    yield from generate_letters()  # boom!
    yield 'end'

print(list(generate_all()))  # ['start', 'a', 'b', 'c', 'end']

That one line handles everything: yields, exceptions, and return values.

Return Values from Sub-generators

You can grab what the sub-generator returns:

def subgen():
    yield 1
    yield 2
    return 'done'

def main():
    result = yield from subgen()
    print('Subgen said:', result)

list(main())
# Output:
# 1
# 2
# Subgen said: done

Coroutines with yield from

Before async/await, people built coroutine patterns on generators. You could send data in:

def echo():
    while True:
        received = yield
        print('Echo:', received)

e = echo()
next(e)          # prime the coroutine
e.send('hello')  # prints 'Echo: hello'

And glue coroutines together with yield from, making simple pipelines.


That’s a quick look at how yield from cleans up generator delegation and hints at coroutines. Next up, we’ll jump into asyncio and the new async/await syntax for real async magic. Happy coding!