The following example defines a coroutine multiply, which waits for a value, multiplies it by a constant factor, and prints the result. Another function, product_table, uses multiply to produce product tables.
def multiply(factor):
    print(f"product table for {factor}")
    while True:
        sent_value = yield
        result = factor * sent_value
        print(f"{factor} x {sent_value} = {result}")
def product_table(coro):
    coro.send(None) # start coroutine
    for value in range(1, 11):
        coro.send(value)
product_table(multiply(3))
running the example produces:
product table for 3
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
I am trying to implement the exact same example in terms of async def and await, but I'm getting nowhere. My original, incorrect expectation was that the following coroutine function using await was equivalent to the coroutine relying on yield:
async def multiply(factor):
    print(f"product table for {factor}")
    while True:
        await sent_value
        result = factor * sent_value
        print(f"{factor} x {sent_value} = {result}")
It may sound stupid that I expected this to work, but to my dull brain it reads "wait for the sent value". This is not the case -- I get NameError: name 'sent_value' is not defined.
So far, my limited understanding is that you can define coroutine functions in terms of yield (as in the first, working example), or in terms of async def and await, as I attempted in the second example. This does not seem to be the case.
My concrete questions are:
- How would you implement the first example in terms of async def?
- Does it even make sense to implement in terms of async def?
I hate that all the freaking examples I've found are in terms of fake pipelines that use time.sleep(0.1) everywhere. I'm trying to make a blog post with examples that use more concrete (if also trivial) pipelines.
[removed erroneous edit]
 
     
     
    