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 #<generator object gen at 0x02801760>
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。

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

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

def mygen():
try:
yield 'something'
except ValueError:
yield 'value error'
finally:
print 'clean' #一定会被执行
gg=mygen()
print gg.next() #something
print 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)
yield def gg():
for x in xrange(4):
print 'xx'+str(x)
yield t=multitask.TaskManager()
t.add(tt())
t.add(gg())
t.run()

结果:

tt0
xx0
tt1
xx1
tt2
xx2
tt3
xx3

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

如果仅仅是实现上面的效果,其实很简单,我们可以自己写一个。主要思路就是将生成器对象放入队列,执行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实现的肯定不止这个功能,有兴趣的童鞋可以看下源码,还是比较简单易懂的。

Python之美[从菜鸟到高手]--生成器之全景分析的更多相关文章

  1. Python之美[从菜鸟到高手]--urlparse源码分析

    urlparse是用来解析url格式的,url格式如下:protocol :// hostname[:port] / path / [;parameters][?query]#fragment,其中; ...

  2. Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)

    我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...

  3. Python之美[从菜鸟到高手]--深刻理解原类(metaclass)

    本来想自己写这篇文章的,可当我读了这篇文章http://blog.jobbole.com/21351/,我打消了这个念头,因为肯定写的没有人家的好,说的通俗易懂,面面俱到.就厚着面皮修改下格式,测试下 ...

  4. Python之美[从菜鸟到高手]--2+2=5

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/yueguanghaidao/article/details/35644165     今天在伯乐在线 ...

  5. Python之美[从菜鸟到高手]--NotImplemented小析

    今天写代码时无意碰到NotImplemented,我一愣.难道是NotImplementedError的胞弟,所以略微研究了一下. NotImplemented故名思议.就是"未实现&quo ...

  6. Python之美[从菜鸟到高手]--Python垃圾回收机制及gc模块详解

    http://blog.csdn.net/yueguanghaidao/article/details/11274737

  7. Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理

    Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理 JDK动态代理的实现及原理 作者:二青 邮箱:xtfggef@gmail.com     微博:http://weibo.com/xtfg ...

  8. Java之美[从菜鸟到高手演变]之设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  9. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

随机推荐

  1. MYSQL 部分事务

    MYSQL 中通过 savepoint 的方式来实现只提交事务的一部分. step 1 : savepoint savepoint_name;. 做标记 step 2 :rollbak to save ...

  2. VS2008编译boost库

    一.下载首先从boost官方主页http://www.boost.org/下载最新版boost安装包,我用的版本是boost.1.49.0二.新建文件夹 如果是使用下载的安装包,那么请将boost安装 ...

  3. TPen的7种Style和16种Mode

    //TPen 的主要属性有四: Color.Width.Style.Mode {Color: 颜色} {Width: 宽度; 默认是 1; 如果赋予 <= 0 的值, 会使用默认值} {Styl ...

  4. 利用netstat和tasklist查看PC的端口占用情况

    经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,如何知道谁占有了我们需要的端口? 1.Windows平台在windows命令行窗口下执行: E:\oracle\ora92\bin>n ...

  5. javascript预加载和延迟加载

    延迟加载javascript,也就是页面加载完成之后再加载javascript,也叫on demand(按需)加载,一般有一下几个方法: What can your tired old page, o ...

  6. jquery实现隐藏显示层动画效果、仿新浪字符动态输入、tab效果

    已经有两年多没登陆csdn账号了,中间做了些旁的事,可是现在却还是回归程序,但改做前端了,虽然很多东西都已忘得差不多了,但还是应该摆正心态,慢慢来,在前端漫游,做一只快乐双鱼. 路是一步一步走出来的, ...

  7. android VoiceRecognition 语音识别并打印到列表上

    package com.example.wenandroid; import java.util.ArrayList; import java.util.List; import android.ap ...

  8. java中文乱码解决之道(五)—–java是如何编码解码的

    原文出处:http://cmsblogs.com/?p=1491 在上篇博客中LZ阐述了java各个渠道转码的过程,阐述了java在运行过程中那些步骤在进行转码,在这些转码过程中如果一处出现问题就很有 ...

  9. O2O领域添新军,正品网加快布局的战略考量

    前不久.正品网採购虚拟运营商30万170号码的招标公告引发了业界的广泛关注.一方面,虚拟运营商正处于"徘徊不定"的十字路口.据业内知情人士透露,眼下12家虚拟运营商企业共放号在20 ...

  10. SQL SERVER 中 实现主表1行记录,子表多行记录 整合成一条虚拟列

    表中有这样的记录,简单的主子表,现要想通过left join 语句把两表关联起来 select * from tbl_diary_reback a left join tbl_diary_reback ...