If Python books are any guide, [coroutines are] the most poorly documented, obscure, and apparently useless feature of Python.
— David Beazley Python author
We find two main senses for the verb “to yield” in dictionaries: to produce or to give way. Both senses apply in Python when we use the
yield keyword in a generator. A line such as
yield item produces a value that is received by the caller of
next(…), and it also gives way, suspending the execution of the generator so that the caller may proceed until it’s ready to consume another value by invoking
next() again. The caller pulls values from the generator.
A coroutine is syntactically like a generator: just a function with the
yield keyword in its body. However, in a coroutine,
yield usually appears on the right side of an expression (e.g.,
datum = yield), and it may or may not produce a value—if there is no expression after the
yield keyword, the generator yields
None. The coroutine may receive data from the caller, which uses
.send(datum) instead of
next(…) to feed the coroutine. Usually, the caller pushes values into the coroutine.
It is even possible that no data goes in or out through the
yield keyword. Regardless of the flow of data,
yield is a control flow device that can be used to implement cooperative multitasking: each coroutine yields control to a central scheduler so that other coroutines can be activated.
When you start thinking of
yield primarily in terms of control flow, you have the mindset ...