python--yield and generator(生成器)简述
1、想象一个场景:
设想,我想要100个素数,然后对它们累加求和。
通常的想法是,找一个一次性至少能提供100个素数的工具(函数),让它把这100个素数交给我(用return 一次性返回含100个素数的列表)。对于100个素数,这显然是可行的。但是,如果我想要无穷多个素数累加,或者非常非常多素数累加,多到几乎可以消耗掉整个内存空间,这时候找一个工具一次性交付这么多数据就显然非常不合适了。
对于之前的设想,我们还可以有另一种想法,就是找一个能不断生产素数的工具,这个工具并不一次交付100个素数,仅在我跟它索要数据的时候它才给出下一个素数(记住,这个工具是有记忆的,它知道我之前取了哪些数,并给出我现在需要的素数。换句话说,它交付给我一个素数后,它的状态被保留了,它仅仅是被挂起而没有被销毁),有点类似母鸡下蛋,拍一拍便下一个蛋,然后就待产了。试想,如果有这个工具,即使让它提供无穷多素数也完全可行,因为它每次只提供一个素数,完全不存在内存耗尽的问题。那么,这个工具存在吗?当然存在,而且名字就叫生成器(generator)。
2、生成器(generator)原理简介:
在python中有一个关键字yield(yield有生产的意思)。当你在函数中使用了yield,你的函数就发生变化了,它变成了生成器(generator)。当你调用这个函数的时候,它不返回值,而是返回一个生成器对象。一个生成器就这样产生了,一个函数加上一个关键字。虽然简单,但是我们还是迷惑,因为我们还不清楚generator的工作流程。那下面就通过一些简单的例子来跟踪一下它吧。
例1:

我们定义了一个函数(def test()),并使用了关键字yield(yield是生产的意思,其后的'hello'就是它即将生产的值了),于是一个generator就产生了(调用test(),返回了一个generator object test)。我们把这个generator赋给变量h。现在我们用next()启动生成器(注:python2.x可以写作h.next()),产生了一个值'hello'。
例2:接例1,如果我们继续使用next(),再次启动generator会怎样呢?

结果发生了StopIterator(终止迭代器)异常。为什么会这样呢,为什么没有产生'hello',难道再次启动generator时没有从函数(test())的第一行开始执行吗?显然是的,不然就真的输出'hello'了。那第二次启动generator时,函数的入口点在哪里?别急,我们先看下面的例子。
例3:

我在原来test()的基础上又增加了一个yield,第一次启动generator输出'hello',第二次启动generator输出'world'。为什么会这样呢,为什么第一次启动generator没有输出'world'?这就要涉及到generator的工作原理了。
当我们使用next()第一次启动generator的时候,函数的入口点在第一行,也就是说,函数从test()的第一行开始执行。当执行到关键字yield处的时候,返回'hello',同时把控制权交给调用方,自己则把当前状态保留(包括变量值,函数执行状态等),准备被再次调用(还记得‘记忆’吗,是的,generator保留了记忆,而普通函数调用完后所有的数据都要销毁,没有记忆存留)。当第二次启动generator时,函数的入口点变成了>>yield 'world',执行完该语句后,generator继续移交控制权,保存当前状态挂起。
回到例2的问题,为什么会产生StopIterator?根据generator的执行原理,第二次启动generator时,函数入口点在yield 'hello'下一行,而它的一下一行什么都没有,自然会返回异常了。那是不是说我在yield 'hello' 后任加一条语句就不会异常,而且可以执行该语句了呢?在例3中我们加了一条yield语句,结果是很满意的。现在我们再加一条打印语句看看情况吧。
例4:

异常又发生了!第二次启动generator时,print 语句没有执行。为什么会这样呢?原来,generator每次启动执行都要寻找关键字yield,当它找不到下一个yield的时候就会说:“StopIterator”。这也就是为什么例3可以顺利执行,例4却会发生异常。
例5:通过前面的例子,你也许已经大概了解了generator的工作原理,要熟练它还得多练习才行。但是,到这里还只是认识了generator的基础而已。在前几个例子中,yield是作为语句出现的,事实上,它还可以是运算式,这个时候我们需要借助h.send(msg)。先看例子,再详细解释吧。

我在函数中加了一个赋值运算符('=')。第二次启动generator时,我使用了send(msg)来发送消息,msg是消息内容,send()可以像next()一样启动generator,同时它还会把作为其参数的msg发送给yield后面的变量a。记住,如果不给a通过send(msg)赋值,a=None。你是不是还想知道,假设有多个像a一样的变量(var = yield ),send(msg)发送的消息会传给谁呢。我们看下面的例子。
例6:

显然,send('he')把消息送给了b,因为b距离下一个yield最近吗?你可以自己试试。你有没有发现,似乎我们写了这么多函数,但是都没有见到return。在generator中return如何自处呢,或者说return和我们的yield是什么关系呢?
在generator中yield相当于普通函数的return,但是又不完全相同。相似点是,函数在执行过程中碰到return/yield时都会移交控制权,不同点是,return移交后会销毁被调函数的一切状态,yield则将函数暂时挂起。
----------------------------------------------------------------------------------
参考资料:
1、提高你的python:解释'yield'和'generators':http://www.oschina.net/translate/improve-your-python-yield-and-generators-explained;
2、python Gossip:yield 产生器:http://openhome.cc/Gossip/Python/YieldGenerator.html;
3、小记python yield 与生成器:http://blog.bitfoc.us/?p=502;
python--yield and generator(生成器)简述的更多相关文章
- Python高级语法之:一篇文章了解yield与Generator生成器
Python高级语法中,由一个yield关键词生成的generator生成器,是精髓中的精髓.它虽然比装饰器.魔法方法更难懂,但是它强大到我们难以想象的地步:小到简单的for loop循环,大到代替多 ...
- generator生成器iterator遍历器和yield
generator方法()返回一个iterator 使用generator时永远先去调用generator()方法 for of对iterator的调用过程(babel参照) 1,_iterator. ...
- 【Python】迭代器、生成器、yield单线程异步并发实现详解
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
- Python入门之迭代器/生成器/yield的表达方式/面向过程编程
本章内容 迭代器 面向过程编程 一.什么是迭代 二.什么是迭代器 三.迭代器演示和举例 四.生成器yield基础 五.生成器yield的表达式形式 六.面向过程编程 ================= ...
- Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍
原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...
- Python高级编程之生成器(Generator)与coroutine(一):Generator
转载请注明出处:点我 这是一系列的文章,会从基础开始一步步的介绍Python中的Generator以及coroutine(协程)(主要是介绍coroutine),并且详细的讲述了Python中coro ...
- Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...
- python yield generator 详解
本文将由浅入深详细介绍yield以及generator,包括以下内容:什么generator,生成generator的方法,generator的特点,generator基础及高级应用场景,genera ...
- python关于type()与生成器generator的用法
如果按这种形式写 type(a)(b) 那此处的b是个可迭代对象,这个对象迭代完成后,再放到type里 from pymysql._compat import range_type, text ...
- Python yield与实现
Python yield与实现 yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...
随机推荐
- deepin下codeblocks更改调试终端
codeblocks建立控制台程序生成完毕后,发现自带的调试终端xterm不能进行复制粘贴操作参考了Ubuntu的更换调试终端的方法,就是把deepin下的deepin-terminal 用作调试终端 ...
- 【反射】利用java反射原理将xml文件中的字段封装成对应的Bean
本例使用的xml解析方式为jdom ... <ROOT> <Consignment> ... </Consignment> </ROOT> 解析xml文 ...
- SpringBoot在IDEA中实现热部署
gradle构建形式 添加依赖 compile("org.springframework.boot:spring-boot-devtools") 其他设置 步骤1 步骤2 按下 C ...
- C - Little Jumper (三分)
题目链接:https://cn.vjudge.net/contest/281961#problem/C 题目大意:青蛙能从一个点跳到第三个点,如图,需要跳两次.问整个过程的最大起跳速度中的最小的. 具 ...
- TeamCity 和 Nexus 的使用
参考:http://www.jianshu.com/p/255a484555d9 TeamCity 安装部署(Linux 环境) 在我讲之前,如果你英文还可以,就到官网这里看下: Installati ...
- UML和模式应用5:细化阶段(2)--细化阶段制品之领域模型
1.前言 领域模型是OO分析中最重要和经典的模型.它阐述了领域中的重要概念: 领域模型作为设计某些软件对象的重要来源,也作为案例研究中探讨的几个制品的输入: 领域模型的范围限定于当前迭代开发的用例场景 ...
- V4L2应用程序框架【转】
转自:https://www.cnblogs.com/hzhida/archive/2012/05/29/2524397.html V4L2是V4L的升级版本,linux下视频设备程序提供了一套接口规 ...
- Linux下查看文件或文件夹大小的命令df 、du、ls
转自:http://www.cnblogs.com/benio/archive/2010/10/13/1849946.html 当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的 ...
- scn 时间
Scn转换成时间: select to_char(scn_to_timestamp(3998591352171),'YYYY-MM-DD HH24:MI:SS') from dual: 时间转换成sc ...
- 在window是下安装hadoop过程
详细见http://www.cnblogs.com/kinglau/archive/2013/08/20/3270160.html