博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python之美[从菜鸟到高手]--生成器之全景分析
阅读量:5906 次
发布时间:2019-06-19

本文共 2649 字,大约阅读时间需要 8 分钟。

    yield指令,可以暂停一个函数并返回中间结果。使用该指令的函数将保存执行环境,并且在必要时恢复。

生成器比迭代器更加强大也更加复杂,需要花点功夫好好理解贯通。

看下面一段代码:

 

def gen():    for x in xrange(4):        tmp = yield x        if tmp == 'hello':            print 'world'        else:            print str(tmp)

     只要函数中包含yield关键字,该函数调用就是生成器对象。

 

 

g=gen()print g   #
print isinstance(g,types.GeneratorType) #True

    我们可以看到,gen()并不是函数调用,而是产生生成器对象。

 

   生成器对象支持几个方法,如gen.next() ,gen.send() ,gen.throw()等。

 

print g.next() # 0

    调用生成器的next方法,将运行到yield位置,此时暂停执行环境,并返回yield后的值。所以打印出的是1,暂停执行环境。

 

 

print g.next() #None  1

     再调用next方法,你也许会好奇,为啥打印出两个值,不急,且听我慢慢道来。

 

     上一次调用next,执行到yield 0暂停,再次执行恢复环境,给tmp赋值(注意:这里的tmp的值并不是x的值,而是通过send方法接受的值),由于我们没有调用send方法,所以

tmp的值为None,此时输出None,并执行到下一次yield x,所以又输出1.

      到了这里,next方法我们都懂了,下面看看send方法。

 

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

      上一次执行到yield 1后暂停,此时我们send('hello'),那么程序将收到‘hello',并给tmp赋值为’hello',此时tmp=='hello'为真,所以输出'world',并执行到下一次yield 2,所以又打印出2.(next()等价于send(None))

 

      当循环结束,将抛出StopIteration停止生成器。

      看下面代码:

 

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

正如你所预料的,打印出’nono',由于没有额外的yield,所以将直接抛出StopIteration。

 

 

nonoTraceback (most recent call last):  File "F:\python workspace\Pytest\src\cs.py", line 170, in 
s.next()StopIteration

      看下面代码,理解throw方法,throw主要是向生成器发送异常。

 

 

def mygen():    try:        yield 'something'    except ValueError:        yield 'value error'    finally:        print 'clean'  #一定会被执行gg=mygen()print gg.next() #somethingprint gg.throw(ValueError) #value error  clean

     调用gg.next很明显此时输出‘something’,并在yield ‘something’暂停,此时向gg发送ValueError异常,恢复执行环境,except  将会捕捉,并输出信息。

 

     理解了这些,我们就可以向协同程序发起攻击了,所谓协同程序也就是是可以挂起,恢复,有多个进入点。其实说白了,也就是说多个函数可以同时进行,可以相互之间发送消息等。

     这里有必要说一下multitask模块(不是标准库中的),看一段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()

结果:

 

 

tt0xx0tt1xx1tt2xx2tt3xx3

   如果不是使用生成器,那么要实现上面现象,即函数交错输出,那么只能使用线程了,所以生成器给我们提供了更广阔的前景。 

   如果仅仅是实现上面的效果,其实很简单,我们可以自己写一个。主要思路就是将生成器对象放入队列,执行send(None)后,如果没有抛出StopIteration,将该生成器对象再加入队列。

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()

  当然,multitask实现的肯定不止这个功能,有兴趣的童鞋可以看下源码,还是比较简单易懂的。

 

 

转载地址:http://zvcpx.baihongyu.com/

你可能感兴趣的文章
单点登录加验证码例子
查看>>
[T-SQL]从变量与数据类型说起
查看>>
occActiveX - ActiveX with OpenCASCADE
查看>>
BeanUtils\DBUtils
查看>>
python模块--os模块
查看>>
Java 数组在内存中的结构
查看>>
《关爱码农成长计划》第一期报告
查看>>
学习进度表 04
查看>>
谈谈javascript中的prototype与继承
查看>>
时序约束优先级_Vivado工程经验与各种时序约束技巧分享
查看>>
minio 并发数_MinIO 参数解析与限制
查看>>
flash back mysql_mysqlbinlog flashback 使用最佳实践
查看>>
mysql存储引擎模式_MySQL存储引擎
查看>>
java 重写system.out_重写System.out.println(String x)方法
查看>>
配置ORACLE 11g绿色版客户端和PLSQL远程连接环境
查看>>
ASP.NET中 DataList(数据列表)的使用前台绑定
查看>>
Linux学习之CentOS(八)--Linux系统的分区概念
查看>>
System.Func<>与System.Action<>
查看>>
asp.net开源CMS推荐
查看>>
csharp skype send message in winform
查看>>