简体   繁体   中英

python3 send() function in generators

According to docs , the send() function:

"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. When send() is called to start the generator, it must be called with None as the argument, because there is no yield expression that could receive the value."

But i can't understand, why "The value argument becomes the result of the current yield expression" is not happened in the following example:

def gen():
    yield 1
    x = (yield 42)
    print(x)
    yield 2

>>>c=gen() #create generator
>>>next(c) #prints '1' and stop execution, which is caused by yield 1
>>>c.send(100) #prints '42', because 'The send() method returns the next value yielded by the generator'
>>>next(c) #prints 'None' and '2'

So why x variable stays 'None' dispite i send 100 to it by c.send(100)? It seems, that yield expression in right hand side works in two steps: first it return the value to generator's caller and the second it returns argument of send function inside generator. And if add extra next(c) before send(42) i'll get expected behavior and programm prints '100'. It's not clear for me from documentation, why these two steps should not happen simultaneously when i call send().

So why x variable stays 'None' dispite i send 100 to it by c.send(100)?

Because the current yield is not the one you think it is, it's the one before.

When you send 100, the generator is still stopped at yield 1 , not yet at yield 42 , hence 100 will be the result of yield 1 , not of yield 42 .

To see this clearer, if you modify the generator in order to retrieve the content of yield 1 in a z variable, you'll see that z does contain 100:

>>> def gen():
...     z = yield 1
...     x = (yield 42)
...     print(x, z)
...     yield 2
... 
>>> c=gen()
>>> next(c)
1
>>> c.send(100)
42
>>> next(c)
None 100
2
>>>

And that's the reason why an extra next() will print 100 . Back to your code:

def gen():
    yield 1  # first next(), stops here (before "getting out" of yield)
    x = (yield 42) # second next(), stops here (before "getting out" of yield),
                   # so, when you send(100), then 100 is given to x and execution goes on, so:
    print(x)  # 100 is printed
    yield 2  # ... and 2.

I think I've figured it out.

c = gen()

You create a genertor in the c variable, there none of the generator's code is executed.

next(c)

Then you use the next() function, the next function go to the next yield statement who is yield 1 here. So this yield returns 1 and stops the generator's execution to try to catch a value.

The next line is c.send(100) , so the yield 1 was waiting for a value and you provided it, but this value isn't saved.
The send method also execute the rest of the generator until the next yield statement who is:

x = (yield 42)

So the yield here return 42 and stops the generator program to try to catch a value. But after that you call

next(c)

And you didn't provided a value so x is None now. Then the rest of the code is executed (until the next yield statement, don't forget)

print(x)
yield 2

So it prints x who is None and then the yield returns 2 and try to catch a value.

Try to write this

c = gen()
next(c)
next(c)
c.send(100)

And it will work (understand why !)

From documentation : The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator.

assume we have following infinite generator:

def infgen():
    a = 0
    while True:
        a = yield a
        a += 1

generato = infgen()

generato.send(None)

output:0

.send(None) is executed almost the same as next()

now we have yeild first value of a = 0 and

code stopped here a = yield a

as value becomes result of the current yield expression

yielded expression is yield a . Result of yielded expresion is a

generato.send(5)

.send(5) we send 5 to a in generator and it continue:

Result of yielded expresion is a = 5

a = 5

a += 1

Go to while loop with a = 5 + 1 = 6

And stops and yield a where a is 6

output:6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM