ruk·si

🐍 Python
Subgenerators

Updated at 2018-06-10 08:58

Generator functions can use subgenerators with yield from keyword. yield from allows a generator to delegate work to another generator.

yield from subgen() makes the subgenerator to take over. Main generator is suspended until the subgenerator terminates.

from typing import Generator

def gen() -> Generator:
    yield from 'AB'
    yield from range(1, 3)

assert list(gen()) == ['A', 'B', 1, 2]

Subcoroutines are common. yield from syntax is important for coroutine generators as the inner generator will be the target of fetches and send().

from typing import Generator, Optional

def outer(numbers) -> Generator:
    while True:
        number = yield from inner()
        numbers.append(number)

# Generator[yield_type, send_type, return_type]
def inner() -> Generator[None, Optional[int], int]:
    number = 0
    while True:
        received = yield  # this is a coroutine
        if received is None:
            return number
        number += received

tallies = []
acc = outer(tallies)

next(acc)  # ensure it is ready to accept values

acc.send(1)
acc.send(1)
acc.send(1)
acc.send(None)  # finish the first tally

acc.send(2)
acc.send(3)
acc.send(None)  # finish the second tally

assert tallies == [3, 5]

Source

  • Fluent Python, Luciano Ramalho