The beauty of Python [from cainiao to masters]-Panoramic Analysis of Generators

Source: Internet
Author: User

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:

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.

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.

print g.next() # 0

Call the next method of the generator and run it to the yield location. The execution environment is paused and the value after yield is returned. So the output is 1, and the execution environment is paused.

print g.next() #None  1

If you call the next method again, you may be curious, why do you print two values? Don't worry, and listen to me slowly.

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.

print g.send('hello') #world  2

The last execution to yield 1 is paused. When we send ('hello'), the program will receive 'hello' and assign the value to TMP as 'hello ', in this case, TMP = 'Hello' is true, so output 'World' and execute it to the next yield 2, SO 2 is printed. (next () is equivalent to send (none ))

When the loop ends, the stopiteration stop generator is thrown.

See the following code:

def stop_immediately(name):    if name == 'skycrab':        yield 'okok'    else:        print 'nono's=stop_immediately('sky')s.next()

As you may expect, printing out 'nono' will directly throw stopiteration because there is no additional yield.

nonoTraceback (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.

Def mygen (): Try: yield 'something 'failed t valueerror: yield 'value error' finally: Print 'clean' # will be executed Gg = mygen () print GG. next () # somethingprint 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:

def tt():    for x in xrange(4):        print 'tt'+str(x)        yielddef gg():    for x in xrange(4):        print 'xx'+str(x)        yieldt=multitask.TaskManager()t.add(tt())t.add(gg())t.run()

Result:

tt0xx0tt1xx1tt2xx2tt3xx3

If you do not use a generator, you can only use threads to implement the above phenomenon, that is, function staggered output. Therefore, 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.

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)                except 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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.