Python: send () behavior in generators

I experimented with generators in python 3 and wrote this pretty far-fetched generator:

def send_gen():
    print("    send_gen(): will yield 1")
    x = yield 1
    print("    send_gen(): sent in '{}'".format(x))
    # yield  # causes StopIteration when left out


gen = send_gen()
print("yielded {}".format(gen.__next__()))

print("running gen.send()")
gen.send("a string")

Conclusion:

    send_gen(): will yield 1
yielded 1
running gen.send()
    send_gen(): sent in 'a string'
Traceback (most recent call last):
  File "gen_test.py", line 12, in <module>
    gen.send("a string")
StopIteration

So, it gen.__next__()reaches the line x = yield 1and gives 1. I thought it xwould be assigned None, then it gen.send()will search for the next statement yield, because x = yield 1"" is used, then get StopIteration.

Instead, it seems that what happened is that a x"string" is sent, which is printed, and then python tries to find the next one yieldand receives StopIteration.

So, I try this:

def send_gen():
    x = yield 1
    print("    send_gen(): sent in '{}'".format(x))


gen = send_gen()
print("yielded : {}".format(gen.send(None)))

Output:

yielded : 1

But now there is no mistake. send()doesn't seem to be trying to find the next statement yieldafter assignment xto None.

? , ?

+5
3

; yield . : StopIteration ; , , . .

, yield, , , . gen.__next__(), gen.send() , yield , gen.send(), None. gen.__next__() gen.send(None), . , , , gen.send() yield first, yield.

, , :

  • gen = send_gen() -. , .

  • gen.__next__(), gen.send(None); yield:

    print("    send_gen(): will yield 1")
    yield 1
    

    . gen.__next__() gen.send(None) 1, , yield 1. , x = ... ! , .

  • gen.send("a string") , . , :

    x = <return value of the yield expression>  # 'a string' in this case
    print("    send_gen(): sent in '{}'".format(x))
    

    , StopIteration .

, StopIteration.

, , yield, , gen.send(), gen.send() None . gen.__next__() (, , next(gen)) "" , yield.

+5

, , .

coroutine, , , "" , yield. . , gen.__next__(), send.

, gen.send(None) ( , None gen.__next__() next(gen)). , StopIteration. , , , , .

, , , -, None, :

TypeError: can't send non-None value to a just-started generator

, "" .

+3

Technically, this is a subroutine, not a generator:

  1. When we call send_gen (), a coroutine object is created
  2. When gen .___ next ____ () is called [We must use next (gen)], the generator function is called, which returns 1 and blocks
  3. When gen.send ("string") is called, the coroutine wakes up and processes the input ("string" is printed here)
  4. Then the coroutine came out
0
source

All Articles