Skip to content
Go back

Coroutines in Python: From Passive Generators to Reactive Code

After learning how to build generator pipelines, the next level was to make them interactive.

This is where coroutines come in.

Unlike traditional generators that only yield values, coroutines can also receive values using send(). This opens the door to more dynamic dataflows — filtering, accumulation, or reacting to external events.


The Coroutine Pattern

A coroutine is a function that contains a yield, but is used differently from a generator. Here’s the classic example:

def grep(pattern):
    print(f"Looking for {pattern}")
    while True:
        line = (yield)
        if pattern in line:
            print(line)

To use it:

g = grep("python")
next(g)              # Prime the coroutine
g.send("hello")      # Ignored
g.send("python rocks")  # Matched and printed

What’s Happening Here?


Building a Coroutine Pipeline

Coroutines become especially powerful when composed into a pipeline:

def printer():
    while True:
        item = (yield)
        print("OUTPUT:", item)

def filter_min(threshold, target):
    while True:
        value = (yield)
        if value >= threshold:
            target.send(value)

Then hook it up:

p = printer()
next(p)
f = filter_min(10, p)
next(f)

for x in [4, 5, 10, 25]:
    f.send(x)

Only 10 and 25 are printed.


Use Cases

Coroutines give you a lightweight way to react to data, rather than just consume it.



Share this post on:

Previous Post
Building a Stack from Scratch in Python
Next Post
Generator Pipelines in Python: Refactoring a Portfolio Report