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
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