Sending into generators
yield is an expression. gen.send(value) resumes a paused generator and makes the waiting yield evaluate to value, so data can flow in as well as out.
def averager():
total = count = 0
average = None
while True:
value = yield average
total += value
count += 1
average = total / count
avg = averager()
next(avg) # run to the first yield
print(avg.send(10), avg.send(20))A new generator has not reached a yield yet, so start it with next(gen), which is the same as gen.send(None). gen.close() raises GeneratorExit at the paused yield so cleanup code runs.
yield from
yield from inner passes along more than values. It forwards send calls to inner, and it evaluates to whatever inner returns. A generator's return x stops it, and x travels in StopIteration.value.
def inner():
n = yield "send me a number"
return n * 2
def outer():
result = yield from inner()
yield f"doubled: {result}"
g = outer()
print(next(g))
print(g.send(21))Your task
Write a generator running_max() that yields the largest number sent to it so far, and None before the first. Write a generator with_result(gen) that passes on everything gen yields, forwards sent values to it, and then yields gen's return value.
The explanation opens here once every check passes.