What does a yield inside a yield do?

yield has two forms, expressions and statements. They're mostly the same, but I most often see them in the statement form, where the result would not be used.

def f():
    yield a thing

But in the expression form, yield has a value:

def f():
    y = yield a thing

In your question, you're using both forms:

def f():
    yield ( # statement
        yield 1 # expression
    )

When you iterate over the resulting generator, you get first the result of the inner yield expression

>>> x=f()
>>> next(x)
1

At this point, the inner expression has also produced a value that the outer statement can use

>>> next(x)
>>>  # None

and now you've exhausted the generator

>>> next(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

To understand more about statements vs expressions, there are good answers in other stackoverflow questions: What is the difference between an expression and a statement in Python?


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.