Discussion on Python generator generator next and send of operation process

  • 2020-05-30 20:33:49
  • OfStack

For a normal generator, the first next call, equivalent to starting the generator, starts at line 1 of the generator function, until the generator function pops out after the yield statement (line 4) is executed the first time.

Then the second next call, after entering the generator function, starts from the next statement (line 5) of the yield statement, and then re-runs to the yield statement. After the execution, the generator function pops out and next is called again, and so on.

Here is one example:

 def consumer():
   r = 'here'
   for i in xrange(3):
     yield r
     r = '200 OK'+ str(i)

 c = consumer()
 n1 = c.next()
 n2 = c.next()
 n3 = c.next()

Now that you know how next() makes a function containing yield execute, let's look at another very important function, send(msg). In fact, next() and send() are similar in the sense of 1. The difference is that send() can pass in the value of yield expression, while next() cannot pass in a specific value, but can only pass in None. Therefore, we can see that c.next () and c.send (None) have the same effect.

It is important to note that on the first call, please use next() or send(None). You cannot use send to send a value that is not None. Otherwise, an error will occur because there is no Python yield statement to receive this value.

Let's highlight the order in which send is executed. At the first send (None) (line 11), start the generator, execute from the first line of the generator function until yield (line 4) is executed the first time, and then the generator function pops out. In this process, n11 is not directly defined.

Now, when you run to send (1), enter the generator function, noting the difference from calling next. This starts at line 4 and assigns 1 to n1, but does not execute the yield part. Next, continue with the next statement of yield, then rerun to the yield statement. After executing, pop out the generator function.

That is, send only starts with one more assignment than next, and the rest of the running process is the same.

 def consumer():
   r = 'here'
   while True:
     n1 = yield r
     if not n1:
     print('[CONSUMER] Consuming %s...' % n1)
     r = '200 OK'+str(n1)

 def produce(c):
   aa = c.send(None)
   n = 0
   while n < 5:
     n = n + 1
     print('[PRODUCER] Producing %s...' % n)
     r1 = c.send(n)
     print('[PRODUCER] Consumer return: %s' % r1)

 c = consumer()

Operation results:

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK1
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK2
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK3
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK4
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK5

Related articles: