Search code examples
pythonpython-3.xgenerator

Yielding inside coroutine


I have the following code.

def gen():
    while True:        # line 2
        d = yield      # line 3
        yield d        # line 4

x = gen()
next(x)

for i in (3, 4, 5):
    print(x.send(i))   # line 10

When I run this, I get:

3
None
5

rather than:

3
4
5

which is what I would expect. I've already gone through several similar questions (including this one) but I still don't understand what is happening here.

My understanding is as follows: We prime the generator by calling next(x), it starts execution and enters the while loop on line 2. On line 3, we have a yield statement and execution pauses. On line 10, we send the value 3. Execution resumes on line 3, d is set to 3, and we yield back d. On line 10, send returns the yielded value (3). The generator continues execution until we are back to the yield statement on line 3, etc.

Is this incorrect? What am I doing wrong here?


Solution

  • x = yield y does two things:

    1. Return y.
    2. Assign the next sent value to x.

    Without y, None gets returned. Without x =, the sent value just gets thrown away.

    So what happens here is:

    code         effects         comments
    ---------------------------------------------
    d = yield    return None     ok, you ignore it
                 d = 3
    yield d      return 3        gets printed
                 Throw away 4
    d = yield    return None     gets printed
                 d = 5
    yield d      return 5        gets printed
    

    You can fix it like this, always storing and returning every sent value:

    def gen():
        d = None  # or `d = yield`, either works, just differently
        while True:
            d = yield d