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

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

看下面一段代码:

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

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

[python]

g=gen()

print g   #

print isinstance(g,types.GeneratorType) #True

g=gen()

print g   #

print isinstance(g,types.GeneratorType) #True    我们可以看到,gen()并不是函数调用,而是产生生成器对象。

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

[python]

print g.next() # 0

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

[python]

print g.next() #None  1

print g.next() #None  1     再调用next方法,你也许会好奇,为啥打印出两个值,不急,且听我慢慢道来。

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

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

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

[python]

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

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

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

看下面代码:

[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() 正如你所预料的,打印出’nono',由于没有额外的yield,所以将直接抛出StopIteration。

[python]

nono

Traceback (most recent call last):

File "F:python workspacePytestsrccs.py", line 170, in

s.next()

StopIteration

nono

Traceback (most recent call last):

File "F:python workspacePytestsrccs.py", line 170, in

s.next()

StopIteration

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

[python]

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

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使用的简单代码:

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

结果:

[python]

tt0

xx0

tt1

xx1

tt2

xx2

tt3

xx3

tt0

xx0

tt1

xx1

tt2

xx2

tt3

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

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

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

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

except StopIteration:

pass

else:

self._queue.put(gen)

t=Task()

t.add(tt())

t.add(gg())

t.run()

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

python之美_Python之美[从菜鸟到高手]--生成器之全景分析相关推荐

  1. pytest测试实战 电子书_电子书丨Selenium 3+Python 3自动化测试项目实战:从菜鸟到高手...

    ▊<Selenium 3+Python 3自动化测试项目实战:从菜鸟到高手> 田春成 著 电子书售价:39.5元 2019年9月出版 Selenium是目前非常流行的一种自动化测试工具.本 ...

  2. python3自动化测试书籍推荐_免费送书 | 《Selenium 3+Python 3自动化测试项目实战:从菜鸟到高手》...

    点击上方蓝色字体,关注我们 免费送书 2019年就剩「2个月」了,你的读书计划进行得如何? 莫踌躇,光荣之路马上送你本书! 读完它,请为你的2019年画上个美丽的圈圈! <Selenium 3+ ...

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

    urllib提供了较好的封装,可以很方便的读取http,ftp,file等协议数据,本篇只关注http.urllib的底层还是使用httplib模块,相比于httplib,urllib接口更加好用,功 ...

  4. python gui模板_Python GUI 编程(Tkinter) | 菜鸟教程

    Python GUI编程(Tkinter) Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的 ...

  5. python数据分析图_Python数据分析:手把手教你用Pandas生成可视化图表的教程

    大家都知道,Matplotlib 是众多 Python 可视化包的鼻祖,也是Python最常用的标准可视化库,其功能非常强大,同时也非常复杂,想要搞明白并非易事.但自从Python进入3.0时代以后, ...

  6. python网格搜索法_Python中基于网格搜索算法优化的深度学习模型分析糖尿病数据...

    介绍 在本教程中,我们将讨论一种非常强大的优化(或自动化)算法,即网格搜索算法.它最常用于机器学习模型中的超参数调整.我们将学习如何使用Python来实现它,以及如何将其应用到实际应用程序中,以了解它 ...

  7. python pymysql实例_Python使用pymysql模块操作mysql增删改查实例分析

    Python使用pymysql模块操作mysql增删改查实例分析 发布时间:2020-09-30 16:42:12 来源:脚本之家 阅读:92 本文实例讲述了Python使用pymysql模块操作My ...

  8. python 法律检索_Python爬虫进阶必备 | 某裁判文书检索网站加密分析与自动登录实现...

    抓包分析 先抓包分析一下登录的请求[图1-1] 图1-1 按照加密的参数,我们一个个分析. 首先是 _csrf ,这个参数比较简单,一般是用来防止跨域***的,感兴趣的朋友可以借助搜索引擎了解一下,不 ...

  9. python在线爬虫_Python爬虫偷懒神器!快速一键生成Python爬虫请求头

    今天介绍个神奇的网站!堪称爬虫偷懒的神器! 我们在写爬虫,构建网络请求的时候,不可避免地要添加请求头( headers ),以 mdn 学习区为例,我们的请求头是这样的: 一般来说,我们只要添加 us ...

最新文章

  1. 删除Win7隐藏的系统分区
  2. CV:基于face库利用cv2调用摄像头(或视频)根据人脸图片实现找人(先指定要识别已知人脸的文件夹转为numpy_array+输入新图片遍历已有numpy_array)
  3. python备份发包脚本_Python备份脚本,python
  4. mysql 5.6 5.7 并存_centos同时运行mysql5.6和mysql5.7
  5. JS重新来过之------------[String对象]
  6. LeetCode 654. 最大二叉树(递归)
  7. OS + macOS Mojave 10.14.4 / sushi / ssh-keygen / ssh-copy-id
  8. [转]Windows 性能监视器工具-perfmon
  9. wamp php不可用_PHPWAMP开启php
  10. Mac墨刀怎么导出HTML,mockingbot墨刀中文使用说明.pdf
  11. win0如何查看计算机工作组,win10家庭版如何查看工作组计算机
  12. C++11新特性,推荐使用emplace_back()替换push_back()的原因
  13. 计算机如何驱动无线网络,电脑如何安装全民WiFi驱动
  14. window电脑 休眠后无法唤醒 解决办法
  15. 中国程序员最容易读错的70个英文单词,非常值得一看!
  16. 电脑垃圾,怎么清理电脑垃圾 让电脑全面瘦身
  17. WebDav的几种应用方法
  18. 小米android手机密码忘了怎么解锁,小米5忘记了锁屏密码怎么办 小米5忘记锁屏密码的解决方法...
  19. Microsoft Mathematics(微软数学软件)
  20. 在中端5G手机市场,小米要以性能碾压其他竞争对手

热门文章

  1. 2019手卫生定义_2021年卫生资格考试部分科目大纲和教材变化归总!
  2. linux 块编辑,vim中的可视块编辑
  3. vue 定义全局弹框_用vue/react写一个全局提示弹框
  4. HDU4417 Super Mario 主席树
  5. 使用 NVM 管理不同的 Node.js 版本
  6. Javascript 面向对象编程
  7. 其实,这仅仅是个开始
  8. 搭建Android开发环境的介绍
  9. c#使用HttpClient调用WebApi
  10. C#多线程与UI响应 防止界面假死不响应(子线程创建的窗体获取消息响应用Application.DoEvent )