Python之美[从菜鸟到高手]--生成器之全景分析
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之美[从菜鸟到高手]--生成器之全景分析的更多相关文章
- Python之美[从菜鸟到高手]--urlparse源码分析
urlparse是用来解析url格式的,url格式如下:protocol :// hostname[:port] / path / [;parameters][?query]#fragment,其中; ...
- Python之美[从菜鸟到高手]--一步一步动手给Python写扩展(异常处理和引用计数)
我们将继续一步一步动手给Python写扩展,通过上一篇我们学习了如何写扩展,本篇将介绍一些高级话题,如异常,引用计数问题等.强烈建议先看上一篇,Python之美[从菜鸟到高手]--一步一步动手给Pyt ...
- Python之美[从菜鸟到高手]--深刻理解原类(metaclass)
本来想自己写这篇文章的,可当我读了这篇文章http://blog.jobbole.com/21351/,我打消了这个念头,因为肯定写的没有人家的好,说的通俗易懂,面面俱到.就厚着面皮修改下格式,测试下 ...
- Python之美[从菜鸟到高手]--2+2=5
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/yueguanghaidao/article/details/35644165 今天在伯乐在线 ...
- Python之美[从菜鸟到高手]--NotImplemented小析
今天写代码时无意碰到NotImplemented,我一愣.难道是NotImplementedError的胞弟,所以略微研究了一下. NotImplemented故名思议.就是"未实现&quo ...
- Python之美[从菜鸟到高手]--Python垃圾回收机制及gc模块详解
http://blog.csdn.net/yueguanghaidao/article/details/11274737
- Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理
Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理 JDK动态代理的实现及原理 作者:二青 邮箱:xtfggef@gmail.com 微博:http://weibo.com/xtfg ...
- Java之美[从菜鸟到高手演变]之设计模式
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
随机推荐
- JSONObject和JSONArray
点击下载json工具 点击下载支持jar包 1.从Object到String 要先用Object对象构造一个JSONObject或者JSONArray对象,然后调用它的toString()方法即可 ( ...
- 在 Linux ubuntu 上安装 *.sh 文件
简单说来就两步: 增加可执行权限 执行 事情是这样的,打算在 ubuntu 上安装一个 NetBeans IDE 来学习 Java,但是下载下来的文件是 .sh 格式的.图形界面下右键没有执行的选项. ...
- 重启VirtualBox里面的系统提示VT-x features locked or unavailable in MSR错误
有次不小心设置了一下virtualbox里面的一些配置,然后启动系统时出现了如下提示 在网上找了一些资料尝试了一些方法偶然有一次成功 原来是自己把那个cpu个数设置成了2,改成1就好了,不知道为什么做 ...
- MySQL必知必会 学习笔记(一)
第一章 了解SQL 模式: 关于数据库和表的布局以及特性的信息.[描述表可以存储什么样的数据,数据如何分解,各部分信息如何命名等等,可以用来描述数据库中特定的表以及整个数据库(和其中表的关系)] ...
- makefile编写差异
由于zlib动态库在linux下引用的问题引出了对于简练的makefile的学习.之前通过看网络上的一些文章自己也算简单了解如何编写一个makefile,可总是不那么美观,今天经过辉哥的指点,对于ma ...
- Java WebService把Date类型转换成XMLGregorianCalendar
JavaEE 的WebService中的Date类型在Web应用中调set方法的时候,默认情况下,JAXB将xsd:date, xsd:time, 和xsd:dateTime映射为XMLGregori ...
- iOS 的 APP 如何适应 iPhone 5s/6/6Plus 三种屏幕的尺寸?(转)
原文:http://www.niaogebiji.com/article-4379-1.html?utm_source=tuicool 初代iPhone 2007年,初代iPhone发布,屏幕的宽高是 ...
- Oracle初级入门 根据某字段重复只取一条记录,并计计算重复条数
在平常开发中,去重复数据经常使用到,本人新手,接触Oracle也不久,开发中用到的小知识点,记录一下,老鸟可绕道,如果有写错的,请指正. 去重复记录可以使用distinct,当只查询一列数据时,可以轻 ...
- asp.net 使用HttpModule记录全局错误
以前使用Global.asax记录全局的错误日志觉得挺好用,但是如果一个解决方案下有N多个项目,每个下边都需要加一个并且代码都还是重复的,终于有一天无法再忍受这种模式,考虑到HttpModule,直接 ...
- ResultSet与Result
微软的.NET平台上面的数据访问有一个特点,就是数据查询的结果,可以放在内存中,以XML格式进行描述,不需要一直与数据库保持在线连接,用DataSet + Data Adapter来实现! 而在JDB ...