Yield command. You can pause a function and return intermediate results. The function that uses this command will save the execution environment and restore it if necessary.
The generator is more powerful and complex than the iterator, so it takes some time to understand it.
See the following code:
[Python]
Def gen ():
For x in xrange (4 ):
Tmp = yield x
If tmp = 'hello ':
Print 'World'
Else:
Print str (tmp)
Def gen ():
For x in xrange (4 ):
Tmp = yield x
If tmp = 'hello ':
Print 'World'
Else:
Print str (tmp)
As long as the function contains the yield keyword, this function call is the generator object.
[Python]
G = gen ()
Print g # <generator object gen at 0x02801760>
Print isinstance (g, types. GeneratorType) # True
G = gen ()
Print g # <generator object gen at 0x02801760>
Print isinstance (g, types. GeneratorType) # True we can see that gen () is not a function call, but a generator object.
The generator object supports several methods, such as gen. next (), gen. send (), and gen. throw.
[Python]
Print g. next () #0
Print g. next () #0 calls the next method of the generator and runs to the yield position. The execution environment is paused and the value after yield is returned. So the output is 1, and the execution environment is paused.
[Python]
Print g. next () # None 1
Print g. next () # None 1 then call the next method. You may wonder why I printed two values, so I am not in a hurry.
The last call to next, execute to yield 0 to pause, execute the recovery environment again, and assign a value to tmp (Note: The tmp value here is not the value of x, but the value accepted by the send method). Because we didn't call the send method
The tmp value is None. At this time, the output is None and the execution is to the next yield x. Therefore, the output is 1.
Now, we understand the next method. Let's take a look at the send method.
[Python]
Print g. send ('hello') # world 2
Print g. send ('hello') # The last time world 2 was executed to yield 1, it was paused. Now we send ('hello'), then the program will receive 'hello ', assign a value to tmp as 'Hello'. In this case, tmp = 'Hello' is true, so output 'World' and run it to the next yield 2, so print 2 again. (next () is equivalent to send (None ))
When the loop ends, the StopIteration stop generator is thrown.
See the following code:
[Python]
Def stop_immediately (name ):
If name = 'skycrab ':
Yield 'okok'
Else:
Print 'nono'
S = stop_immediately ('sky ')
S. next ()
Def stop_immediately (name ):
If name = 'skycrab ':
Yield 'okok'
Else:
Print 'nono'
S = stop_immediately ('sky ')
S. next (), as you expected, prints 'nono'. As there is no additional yield, StopIteration will be thrown directly.
[Python]
Nono
Traceback (most recent call last ):
File "F: \ python workspace \ Pytest \ src \ cs. py", line 170, in <module>
S. next ()
StopIteration
Nono
Traceback (most recent call last ):
File "F: \ python workspace \ Pytest \ src \ cs. py", line 170, in <module>
S. next ()
StopIteration
Take a look at the following code to understand the throw method. throw mainly sends an exception to the generator.
[Python]
Def mygen ():
Try:
Yield 'something'
Failed t ValueError:
Yield 'value error'
Finally:
Print 'clean' # will be executed
Gg = mygen ()
Print gg. next () # something
Print gg. throw (ValueError) # value error clean
Def mygen ():
Try:
Yield 'something'
Failed t ValueError:
Yield 'value error'
Finally:
Print 'clean' # will be executed
Gg = mygen ()
Print gg. next () # something
Print gg. throw (ValueError) # value error clean
When gg. next is called, it is obvious that 'something 'is output at this time, and it is paused at yield 'something'. At this time, a ValueError exception is sent to gg to restore the execution environment. Then, the Progress T will capture and output information.
After understanding this, we can initiate an attack to the collaborative program. The so-called collaborative program can be suspended, restored, and there are multiple entry points. To put it bluntly, that is to say, multiple functions can be performed at the same time, and messages can be sent between them.
Here we need to talk about the multitask module (not in the standard library). Let's look at the simple code used by multitask:
[Python]
Def tt ():
For x in xrange (4 ):
Print 'TT' + str (x)
Yield
Def gg ():
For x in xrange (4 ):
Print 'xx' + str (x)
Yield
T = multitask. TaskManager ()
T. add (tt ())
T. add (gg ())
T. run ()
Def tt ():
For x in xrange (4 ):
Print 'TT' + str (x)
Yield
Def gg ():
For x in xrange (4 ):
Print 'xx' + str (x)
Yield
T = multitask. TaskManager ()
T. add (tt ())
T. add (gg ())
T. run ()
Result:
[Python]
Tt0
Xx0
Tt1
Xx1
Tt2
Xx2
Tt3
Xx3
Tt0
Xx0
Tt1
Xx1
Tt2
Xx2
Tt3
Xx3 if the generator is not used, you must implement the above phenomenon, that is, the function staggered output, so you can only use the thread, so the generator provides us with a broader prospect.
If we only implement the above results, it is actually very simple. We can write one by ourselves. The main idea is to put the generator object into the queue. After sending (None) is executed, if StopIteration is not thrown, the generator object will be added to the queue.
[Python]
Class Task ():
Def _ init _ (self ):
Self. _ queue = Queue. Queue ()
Def add (self, gen ):
Self. _ queue. put (gen)
Def run (self ):
While not self. _ queue. empty ():
For I in xrange (self. _ queue. qsize ()):
Try:
Gen = self. _ queue. get ()
Gen. send (None)
Optional t StopIteration:
Pass
Else:
Self. _ queue. put (gen)
T = Task ()
T. add (tt ())
T. add (gg ())
T. run ()
Class Task ():
Def _ init _ (self ):
Self. _ queue = Queue. Queue ()
Def add (self, gen ):
Self. _ queue. put (gen)
Def run (self ):
While not self. _ queue. empty ():
For I in xrange (self. _ queue. qsize ()):
Try:
Gen = self. _ queue. get ()
Gen. send (None)
Optional t StopIteration:
Pass
Else:
Self. _ queue. put (gen)
T = Task ()
T. add (tt ())
T. add (gg ())
T. run ()
Of course, the implementation of multitask is certainly not limited to this function. If you are interested, you can check the source code, which is relatively simple and easy to understand.