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表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...
随机推荐
- POJ1236 Network of Schools【强连通】
题意: N(2<N<100)各学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输,问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件 ...
- _vimrc(VimScript脚本语言学习)
Windows下 syntax on "高亮 "缩进 set cindent "set cin set smartindent "set si set auto ...
- HashMap原理分析(JDK1.7.x之前)
HashMap 实现Map.Cloneable.Serializable接口,继承AbstractMap基类. HashMap map = new HashMap<String,String&g ...
- 用winhotkey添加属于自己的快捷键
需求 我要使用Win+N快捷键组合打开指定某个文件! 使用方法 打开winhotkey软件,做以下操作: 此刻,就可以用Win+N组合快捷键来打开指定目录了!
- D - Laying Cables Gym - 100971D (单调栈)
题目链接:https://cn.vjudge.net/problem/Gym-100971D 题目大意:给你n个城市的信息,每一个城市的信息包括坐标和人数,然后让你找每一个城市的父亲,作为一个城市的父 ...
- mysql 原理 ~ binlog
一 简介:我们会持续对binlog进行分析,但是不深入代码二 版本 5.6 格式 GTID和传统格式 传统格式 一 binlog针对具体事务注意点-1 1 u ...
- mysql 开源~canal安装解析
一 简介:今天咱们来聊聊canal的一些东西 二 原理: canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议 mysql ma ...
- session和token
功能是一样的,都是要与浏览器建立连接,获取与客户端对应的用户数据,只不过完成这个功能的实现方式不太一样. 本质上的区别: session的使用方式是客户端cookie里存id,服务端session存用 ...
- datatables 添加excel下载
Datatables 版本 1.10.12 和普通datatables不一样的是: 引入包 <script src="../../vendor/datatables/js/dataTa ...
- Andrew Ng在coursera上的ML视频 知识点笔记(2)
一.由线性回归导出逻辑回归: 二.“一对多”算法解决多分类问题: 三.“过拟合”和“欠拟合”: (1)对线性回归加入正则项: (2)对逻辑回归加入正则项: (3)加入正则项之后的正规方程: