Python Generators, yield and send
Let’s say you’re programming a scoring system for the local rounders team. In rounders, a batter can score a half-rounder or a full-rounder. It’s also possible for one batter to score a half-rounder and another to score a full-rounder off the same ball, for example if a batter on base 3 and the batter hitting both make it round. In this scenario we can’t just increment the score by 1 each time.
So let’s make a generator that will increase by 1/2 each time by default, but will also accept other values to increment by.
def score_tally():
score = 0
default = 0.5
while True:
incr = yield score
score += incr if incr is not None else default
Line 5 is the special one here, that’s what lets us use the send
function, as well as the normal next
function. When using send
, the value is passed to incr
. When using next, yield score
will return None
. This is why we check for None
on line 6, before adding incr
, or default
if incr
is None
. We can then use this generator like so:
>>> bonkers_batters = score_tally()
>>> next(bonkers_batters)
0
>>> next(bonkers_batters)
0.5
>>> next(bonkers_batters)
1
>>> next(bonkers_batters)
1.5
>>> bonkers_batters.send(1)
2.5
>>> bonkers_batters.send(1.5)
4
>>> next(bonkers_batters)
4.5
The Python Docs for Yield mention send
, and the Python Docs for generator gives the bare-bones description. There’s also an async
version, although this one has to be awaited.
Until next time, happy coding. Paul