Generator functions that define consume and produce values are coroutines. The basic premise is that coroutines allow two functions to communicate with each other while running.
The difference between regular generators and coroutines is that coroutines don't simply return values to the calling function but can receive values as well.
Coroutines consume values using a (yield) statement as follows:
value = (yield)
With this syntax, execution pauses at this statement until the object's send method is invoked with an argument
coroutine.send(data)
Then, execution resumes, with value being assigned to the value of data.
def repeater(): while True: received = yield print('Echo:', received) rp = repeater() next(rp) # Start the coroutine rp.send('Hello') rp.send('World') #Echo: First #Echo: Second
Since generators are lazy, you can't just send a value to a brand new generator. Before a value can be sent to the generator, either a result must be fetched using next()
or a send(None)
has to be issued so that the code is actually reached.
For example, say you want to implement a generator coroutine that yields the minimum value it’s been sent so far. Here, the bare yield
prepares the coroutine with the initial minimum value sent in from the outside. Then the generator repeatedly yields the new minimum in exchange for the next value to consider.
def minimize(): current = yield while True: value = yield current current = min(value, current)
The code consuming the generator can run one step at a time and will output the minimum value seen after each input.
it = minimize() next(it) # Start the generator print(it.send(10)) print(it.send(4)) print(it.send(22)) print(it.send(-1)) # 10 # 4 # 4 #-1
The generator function will seemingly run forever, making forward progress with each new call to send
. Like threads, coroutines are independent functions that can consume inputs from their environment and produce resulting outputs. The difference is that coroutines pause at each yield
expression in the generator function and resume after each call to send
from the outside. This is the magical mechanism of coroutines.