What does a yield inside a yield do?

Consider the following code:

    def mygen():
         yield (yield 1)
    a = mygen()
    print(next(a))
    print(next(a))

The output yields:

    1
    None

What does the interpreter do at the "outside" yield exactly?

a is a generator object. The first time you call next on it, the body is evaluated up to the first yield expression (that is, the first to be evaluated: the inner one). That yield produces the value 1 for next to return, then blocks until the next entry into the generator. That is produced by the second call to next, which does not send any value into the generator. As a result, the first (inner) yield evaluates to None. That value is used as the argument for the outer yield, which becomes the return value of the second call to next. If you were to call next a third time, you would get a StopIteration exception.

Compare the use of the send method (instead of next) to change the return value of the first yield expression.

    >>> a = mygen()
    >>> next(a)
    1
    >>> a.send(3)  # instead of next(a)
    3
    >>> next(a)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration

A more explicit way of writing the generator would have been

    def mygen():
        x = yield 1
        yield x

    a = mygen()
    print(a.send(None))  # outputs 1, from yield 1
    print(a.send(5))     # makes yield 1 == 5, then gets 5 back from yield x
    print(a.send(3))     # Raises StopIteration, as there's nothing after yield x

Prior to Python 2.5, the yield statement provided one-way communication between a caller and a generator; a call to next would execute the generator up to the next yield statement, and the value provided by the yield keyword would serve as the return value of next. The generator would also suspend at the point of the yield statement, waiting for the next call to next to resume.

In Python 2.5, the yield statement was replaced* with the yield expression , and generators acquired a send method. send works very much like next, except it can take an argument. (For the rest of this, assume that next(a) is equivalent to a.send(None).) A generator starts execution after a call to send(None), at which point it executes up to the first yield, which returns a value as before. Now, however, the expression blocks until the next call to send, at which point the yield expression evaluates to the argument passed to send. A generator can now receive a value when it resumes.

  • Not quite replaced; kojiro's answer goes into more detail about the subtle difference between a yield statement and yield expression.

From: stackoverflow.com/q/55922302