Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this Python generator/coroutine lose a value? [duplicate]

Reading about Python coroutines, I came across this code:

def countdown(n):
    print("Start from {}".format(n))
    while n >= 0:
        print("Yielding {}".format(n))
        newv = yield n
        if newv is not None:
            n = newv
        else:
            n -= 1

c = countdown(5)
for n in c:
    print(n)
    if n == 5: c.send(2)

which curiously outputs:

Start from 5
Yielding 5
5
Yielding 3
Yielding 2
2
Yielding 1
1
Yielding 0
0

In particular, it misses printing the 3. Why?


The referenced question does not answer this question because I am not asking what send does. It sends values back into the function. What I am asking is why, after I issue send(3), does the next yield, which should yield 3, not cause the for loop to print 3.

like image 788
Ritzymon Avatar asked Jul 19 '17 06:07

Ritzymon


1 Answers

You never checked the return value of your c.send(3) call. In fact, it appears that the send method itself advances the generator, so your missing 3 was yielded in that c.send(3) call.

def countdown(n):
    while n >= 0:
        newv = yield n
        if newv is not None:
            n = newv
        else:
            n -= 1

c = countdown(5)
print(next(c))  
print(c.send(3))
print(next(c))  

The output would be:

5
3
2

It is actually documented:

generator.send(value)

Resumes the execution and “sends” a value into the generator function. The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value.

like image 74
taras Avatar answered Oct 20 '22 01:10

taras