yield

A def containing yield returns a generator instead of running. Each next() runs the body up to the following yield — lazily, and exactly once per value.

FunctionsPython 3 (all)Live demo
yield
def gen():
    yield value
yield from
def gen():
    yield from iterable
receive with send()
received = yield value
Use for
Streams of values, big or infinite sequences, pipelines over files and data
Result
calling the function returns a generator object; yield evaluates to what send() passed (None for next())
Pairs with
next(), for, list(), itertools, yield from, return
Watch out
a generator can be iterated only once — the second pass is empty

Demo

Live evaluation
Ask for one value and look at the log: only one item was made, no matter how big n is.
Try:
Inputs
ninthow many to offer
Code
log = []
def numbers(n):
    for i in range(n):
        log.append(f'made {i}')
        yield i
g = numbers(5)
first = next(g)
(first, log)
Result
(0, ['made 0'])

In the lazy tab the log has a single entry even for a billion — the rest were never computed. With n = 0 the generator has nothing to give, so next() raises StopIteration. In the consumed once tab, the second list() is always empty: generators do not rewind.

Syntax slots

NameTypeRequiredDescription
expressionexpressionno (None)The value handed to the consumer of this step. Omitted → None.
iterableexpressionyesyield from only: every item is passed through, and the expression evaluates to the sub-generator’s return value.

Common patterns

Stream a file line by line
Constant memory, however big the file.
def non_blank(path):
    with open(path) as f:
        for line in f:
            if line.strip():
                yield line.rstrip("\n")
Pipeline of generators
Each stage pulls from the previous one, one item at a time.
def parse(lines):
    for line in lines:
        yield line.split(",")

rows = parse(non_blank("data.csv"))
Flatten with yield from
Delegate to a sub-iterable instead of looping and yielding.
def flatten(tree):
    for node in tree:
        if isinstance(node, list):
            yield from flatten(node)
        else:
            yield node
Generator expression
The one-line form for simple cases.
total = sum(x * x for x in numbers)

Examples

1. A simple generator
def count_up(n): i = 1 while i <= n: yield i i += 1 list(count_up(3))
Returns
[1, 2, 3]
2. Calling it returns a generator
def gen(): yield 1 type(gen()).__name__
Returns
'generator'
3. The body starts at the first next()
def gen(): print('started') yield 1 g = gen() print('created') next(g)
Returns
created started 1
4. Infinite, but lazy
from itertools import islice def naturals(): n = 0 while True: yield n n += 1 list(islice(naturals(), 5))
Returns
[0, 1, 2, 3, 4]
5. yield from flattens
def flat(lists): for lst in lists: yield from lst list(flat([[1, 2], [3]]))
Returns
[1, 2, 3]
6. send() a value in
def echo(): got = yield 'ready' yield f'got {got}' g = echo() (next(g), g.send(42))
Returns
('ready', 'got 42')
7. yield outside a function
compile('yield 1', '<demo>', 'exec')
Returns
SyntaxError: 'yield' outside function

Pitfalls

1. Iterating a generator twice
sum() consumed every value; the generator is now exhausted. Store a list if you need the values again.
reuse the generator
def evens(xs):
    for x in xs:
        if x % 2 == 0:
            yield x
e = evens([1, 2, 3, 4])
total = sum(e)
(total, list(e))
(6, [])
materialise once
def evens(xs):
    for x in xs:
        if x % 2 == 0:
            yield x
e = list(evens([1, 2, 3, 4]))
total = sum(e)
(total, list(e))
(6, [2, 4])
2. Treating a generator like a list
Generators have no length and no indexing — they only know how to produce the next value.
len(generator)
def gen():
    yield 1
    yield 2
len(gen())
TypeError: object of type 'generator' has no len()
list() first
def gen():
    yield 1
    yield 2
len(list(gen()))
2
3. send() before the generator started
A fresh generator is not paused at a yield yet, so there is nothing to receive the value. Prime it with next() first.
send first
def gen():
    x = yield
    yield x * 2
g = gen()
g.send(5)
TypeError: can't send non-None value to a just-started generator
next, then send
def gen():
    x = yield
    yield x * 2
g = gen()
next(g)
g.send(5)
10

When to use

Use it
  • Producing a long or unbounded series without building it in memory
  • Reading files, sockets or paginated APIs item by item
  • Splitting a loop into stages (produce / filter / transform) that each stay simple
Reach for something else
  • You need len(), indexing or several passes → return a list
  • The values are small and few → a list is simpler to debug
  • A one-line transformation → a generator expression (x for x in …)

Notes

CPython impl
A function containing yield is compiled with the generator flag; calling it creates a generator object holding a suspended frame
Return
return value in a generator ends it and sets StopIteration.value — yield from evaluates to it
yield from
Added in 3.3 (PEP 380); it also forwards send() and throw() to the sub-generator

FAQ

return ends the function and hands back one value. yield hands back a value and pauses; the function resumes where it left off on the next next() call. A function that contains yield anywhere becomes a generator function.

History

3.3
Added yield from <expr> to delegate control flow to a subiterator.
3.8
Yield expressions prohibited in the implicitly nested scopes used to implement comprehensions and generator expressions.
3.13
If a generator returns a value upon being closed, the value is returned by close().