Why does the yield expression collapse?

Viewed 73

I was messing around and noticed that the following code yields the value once, while I was expecting it to return a generator object.

def f():
    yield (yield 1) 
f().next() # returns 1

def g():
    yield (yield (yield 1) 
g().next() # returns 1

My question is what is the value of the yield expression and also why are we allowed to nest yield expression if the yield expression collapses?

1 Answers

The value of the yield expression after resuming depends on the method which resumed the execution. If __next__() is used (typically via either a for or the next() builtin) then the result is None. Otherwise, if send() is used, then the result will be the value passed in to that method.

So this:

def f():
    yield (yield 1) 

Is equivalent to this:

def f():
    x = yield 1
    yield x

Which in this case (since you're not using generator.send()) is equivalent to this:

def f():
    yield 1
    yield None

Your code is only looking at the first item yielded by the generator. If you instead call list() to consume the whole sequence, you'll see what I describe:

def f():
    yield (yield 1)

def g():
    yield (yield (yield 1)) 


print(list(f()))
print(list(g()))

Output:

$ python3 yield.py 
[1, None]
[1, None, None]

If we iterate the generator manually (as you have), but .send() it values, then you can see that yield "returns" this value:

gen = f()
print(next(gen))
print(gen.send(42))

Output:

$ python3 yield_manual.py 
1
42
Related