🎓 A1Learner
🔍

Python Generator Methods

Generator methods let a caller control a paused generator.

Send a value in

Priming means starting the generator. It now waits at the first yield.

def echo():
    message = yield "waiting"
    yield message

gen = echo()
print(next(gen))
print(gen.send("hello"))

What send() gives back

send() does two jobs at once. The value goes in and the next yield comes out.

def running_total():
    total = 0
    while True:
        value = yield total
        total += value

gen = running_total()
print(next(gen))
print(gen.send(5))
print(gen.send(7))

Raise inside with throw()

throw() raises at the paused yield line. The generator can catch that error.

def careful():
    try:
        yield 1
        yield 2
    except ValueError:
        yield "caught it"

gen = careful()
print(next(gen))
print(gen.throw(ValueError))

Close it with close()

close() raises GeneratorExit inside. Clean up there and do not yield again.

def tidy():
    try:
        yield 1
        yield 2
    except GeneratorExit:
        print("cleaning up")
        raise

gen = tidy()
print(next(gen))
gen.close()
try:
    next(gen)
except StopIteration:
    print("closed")

Delegate with yield from

yield from passes every value out. The small generator does the work.

def letters():
    yield "a"
    yield "b"

def outer():
    yield from letters()
    yield "c"

print(list(outer()))

Example

def running_average():
    total = 0.0
    count = 0
    average = None
    while True:
        value = yield average
        total += value
        count += 1
        average = total / count

averages = running_average()
next(averages)
print(averages.send(10))
print(averages.send(20))
print(averages.send(30))
print(averages.send(40))

Key points

  • Priming: run next() once so the generator waits at its first yield
  • Use send(value) to resume a generator and feed a value in
  • send() returns the next value the generator yields
  • Use throw(type) to raise an error inside the generator
  • Use close() to stop a generator early
  • GeneratorExit: the signal close() raises inside the generator
  • Use yield from to delegate to a sub-generator and pass its values out
  • These methods control a generator while it sits paused.

In this example, running_average waits at yield. The first next() call primes it. That call gets None as the starting average. Each send() call then feeds one new number in. The generator adds the number to total. It adds one to count. It then works out the new average. The yield sends that average back out. The four prints show the average after each new number.

Note

In Python, send() on a fresh generator can only send None.

Prime it first with next().

Try it Yourself

Edit the code, then press Run.

Running is simulated · Python Playground

Exercise

You want to send 10 into a fresh generator. What must you do first?