Python generators
send function
Python programming
generator functions
Python iterators

What is the purpose of the send function on Python generators?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Most Python developers use generators only as lazy iterators with yield and next(). The send() method adds a second channel: it lets the caller push a value back into the paused generator. That turns a generator from a one-way producer into a small coroutine-like state machine.

What send() Actually Does

When a generator is paused at a yield expression, calling send(value) resumes execution and makes that yield expression evaluate to value.

Basic example:

python
1def echo():
2    received = yield "ready"
3    yield f"got: {received}"
4
5
6g = echo()
7print(next(g))          # ready
8print(g.send("hello"))  # got: hello

The important detail is that the value sent by send() is received inside the generator where execution was suspended.

Why send(None) or next() Comes First

You cannot send a real value into a generator before it reaches the first yield. The generator has to be “primed” first.

python
1def counter():
2    increment = yield 0
3    while True:
4        increment = 1 if increment is None else increment
5        increment = yield increment
6
7
8g = counter()
9print(next(g))  # or g.send(None)

If you call g.send(5) immediately on a fresh generator, Python raises TypeError because there is no paused yield ready to receive the value yet.

Two-Way Communication Pattern

send() is useful when the generator should react to caller input while maintaining internal state.

python
1def accumulator():
2    total = 0
3    while True:
4        value = yield total
5        if value is not None:
6            total += value
7
8
9g = accumulator()
10print(next(g))       # 0
11print(g.send(5))     # 5
12print(g.send(10))    # 15
13print(g.send(None))  # 15

This is more expressive than repeatedly rebuilding state in external code because the generator owns its own internal state transitions.

Historical Coroutine Use

Before async and await, Python used generator-based coroutines heavily. send() was central to that style because it allowed event loops and schedulers to push values back into paused computations.

A simplified coroutine-style example:

python
1def greeter():
2    name = yield "Who are you?"
3    yield f"Hello, {name}"
4
5
6g = greeter()
7question = next(g)
8print(question)
9answer = g.send("Ava")
10print(answer)

Today, native async def is usually a better abstraction for real asynchronous workflows, but understanding send() helps explain older coroutine libraries and Python’s evolution.

Relationship to throw() and close()

Generators also support throw() and close(), which complete the control surface around paused execution:

  • 'send(value) injects a normal value.'
  • 'throw(exc) injects an exception.'
  • 'close() requests termination.'

Together, these methods make generators programmable suspension points rather than simple iterators.

When send() Is the Right Tool

Use send() when:

  • the generator maintains internal state.
  • the caller needs to influence the next step of computation.
  • you are implementing or reading coroutine-like logic.

Avoid it when a normal function, iterator, or class would be clearer. send() is powerful, but it also makes control flow less obvious to casual readers.

Common Pitfalls

  • Calling send(value) before priming the generator with next() or send(None).
  • Forgetting that the value is delivered into the paused yield expression.
  • Using send() where a simple function or object would be easier to read.
  • Confusing generator-based coroutines with modern async and await.
  • Ignoring StopIteration handling when the generator completes.

Summary

  • 'send() lets callers push values back into a paused generator.'
  • It turns generators into two-way stateful computations, not just lazy iterators.
  • A generator must be primed before receiving a non-None value.
  • 'send() was foundational for older coroutine patterns in Python.'
  • Use it when two-way control flow is genuinely helpful, not just because it exists.

Course illustration
Course illustration

All Rights Reserved.