啊哈,yield
文章出处:http://www.cnblogs.com/winstic/,请保留此连接
在python编程中,我们经常会看到函数中带有yield关键字,但请注意,此时的函数不再是我们熟知的一般函数,而是所谓的generator(生成器)
生成器
对于生成器,可以对比于列表来看,我们在循环代码中经常会使用range()产生一个list对象,继而在for循环下依次遍历,
for i in range(1000):
print i
或者是使用列表生成式生成一个list对象:
[x * x for x in range(1000)]
这么做确实很方便,但这有个很大的缺点,我们所生产的list对象在程序运行过程中是存放在内存中的,占用内存大小与list规模有关,若要在编程时控制内存的占用,最好不要使用list。
相比于list对象对内存的占用,generator有很大的优势,generator保存的是算法,不会生成所有的元素,而只是在调用next()时产生一个元素,很好的优化了内存占用的问题,可以通过next方法访问数据,当没有数据时会自动抛出StopIteration异常
>>> gener = (x * x for x in [1, 2, 3])
>>> g = (x * x for x in [1, 2, 3])
>>> g
<generator object <genexpr> at 0x02534968>
>>> g.next()
1
>>> g.next()
4
>>> g.next()
9
>>> g.next() Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
g.next()
StopIteration
>>>
这么做的话难免有些繁琐,还好在for循环中会帮我们实现next方法的调用也可以这么实现
>>> for i in g:
print i
yield 初体验
以上所实现的generator只是规律十分简单的,这很好实现,只需要类似于列表生成式的简单语法即可,那么对于其他的数列计算如何实现呢,例如斐波那契数列,它的定义虽然简单:除第一、二个数据外,所有的数据均是其前两个数据之和;如果我们通过一般函数实现,无疑当数列规模很大时,占用大量内存
>>> def fib(N):
n, a, b = 0, 0, 1
while n < N:
print b
a, b = b, a + b
n = n + 1
那么如何将上述方法转换为generator加以实现呢,很简单,只需要将print b 替换为yield b即可,我们可以试一下:
>>> def fib(N):
n, a, b = 0, 0, 1
while n < N:
yield b
a, b = b, a + b
n = n + 1 >>> fib(5)
<generator object fib at 0x02530F80>
>>> for i in fib(5):
print i 1
1
2
3
5
加了yield关键字后的函数是如何执行的呢,不应该说是函数,这时应该称为generator;我们调用fib(5)并不会执行函数,而是返回一个generator对象,真正的执行是在调用next方法(for循环中自动调用next()),每次循环都会执行fib内的代码,遇到yield则返回一个迭代值(类似于中断);在下次循环时执行yield的下一语句,直至遇到下一个yield。
yield 协程
协程(coroutine)也叫微线程,相比于多线程更为高效,因为协程是多个程序在一个线程中执行,没有线程间切换的开销;同时在协程中不需要加锁机制,因为在一个线程中不存在变量冲突问题。
例如经典问题(生产者-消费者问题)就可以使用协程机制实现,相比于多线程更为高效
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print 'consumer %s' % n
r = 'OK' def produce(c):
c.next()
n = 0
while n < 5:
n = n + 1
print 'produce %s' % n
r = c.send(n)
print 'consumer return %s' % r
c.close() if __name__ == '__main__':
c = consumer()
produce(c)
produce 1
consumer 1
consumer return OK
produce 2
consumer 2
consumer return OK
produce 3
consumer 3
consumer return OK
produce 4
consumer 4
consumer return OK
produce 5
consumer 5
consumer return OK
执行结果
在上述代码中,consumer是一个生成器,执行过程中首先通过consumer产生generator对象c,
我们在执行到produce(c)的next方法时,才切换到生成器函数consumer中执行,
在consumer中遇到yield中断,又切回到produce中
在produce中的c.send(n):主要干两件事:1.将n添加到生成器中,2.返回下一个yield值(return next());所以当我们运行到send方法时,内含next机制进而切换到consumer函数中执行(传入参数n),得到返回值'OK'(在下一个yield中返回)
。。。。。
最后在produce中关闭迭代器c.close()
总结:
- 在generator中不同于一般函数,调用方法名不会执行,只会返回一个generator对象,只有在调用next方法时才会执行
- 一个函数中加入yield则变为generator,函数执行到yield时中断,下次迭代时定位到yield的下一条语句;yield还常用于文件的读取,用read()会造成不可预测的内存占用问题,而使用yield可以实现内存只存储每次迭代过程中固定的size
啊哈,yield的更多相关文章
- Python 生成器与迭代器 yield 案例分析
前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...
- node 异步回调解决方法之yield
先看如何使用 使用的npm包为genny,npm 安装genny,使用 node -harmony 文件(-harmony 为使用es6属性启动参数) 启动项目 var genny= require( ...
- yield生成器及字符串的格式化
一.生成器 def ran(): print('Hello world') yield 'F1' print('Hey there!') yield 'F2' print('goodbye') yie ...
- Python中的生成器与yield
对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...
- Python yield函数理解
Python中的yield函数的作用就相当于一个挂起,是不被写入内存的,相当于一个挂起的状态,用的时候迭代,不用的时候就是一个挂起状态,挂起状态会以生成器的状态表现
- ecma6 yield
function * generator(k){ console.log('begin'); var x = yield k; console.log('x:',x); var y = yield x ...
- Python yield与实现
Python yield与实现 yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...
- 可惜Java中没有yield return
项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...
- 使用yield进行异步流程控制
现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...
- GetEnumerator();yield
GetEnumerator()方法的实质实现: 说明:只要一个集合点出GetEnumerator方法,就获得了迭代器属性,就可以用MoveNext和Current来实现foreach的效果,如上图. ...
随机推荐
- linux驱动开发之HelloWorld
最近实习,公司项目搞的是平板开发,而我分配的任务是将驱动加载到内核中. 准备工作,必要知识了解:加载有两种方式,一种是动态加载和卸载即模块加载,另一种是直接编译进入内核:Linux内核把驱动程序划分为 ...
- kafka leader 服务器均衡。
Whenever a broker stops or crashes leadership for that broker's partitions transfers to other replic ...
- MySQL查询过程中出现lost connection to mysql server during query 的解决办法
window7 64位系统,MySQL5.7 问题:在使用shell进行数据表更新操作的过程,输入以下查询语句: ,; 被查询的表记录数达到500W条,在查询过程中出现如题目所示的问题,提示" ...
- jump_ur.php通知模板
<title>出错啦~~~</title> <script language="javascript" type="text/javascr ...
- 下载的chm手册打不开的解决方法?
用ie或者chrome等浏览器下载文件的时候,都会给文件加上一个默认的保护,右键这个文件,打开属性对话框,然后在第一个的选项卡的安全的部分,有个解除这个保护的按钮点下然后确定保存,再打开chm文件就不 ...
- winform渐变窗口显示/关闭
//渐渐的消失 for (int iNum = 10; iNum >= 0; iNum --) { //变更窗体的不透明度 this.Opacity = 0.1 * iNum; //暂停 Sys ...
- myNote
源码地址 :http://450640526.ys168.com/ 编辑器是WEBBWOSER制作的 你的Internet Explorer的版本至少要是8.0的否则用不了 还有很多BUG 很多功能没 ...
- MapReduce优化
Combiner和Partitioner是用来优化MapReduce的,可以提高MapReduce的运行效率.下面我们来具体学习这两个组件 Combiner 我们以WordCount为例,首先通过下面 ...
- Optimized Pagination using MySQL---reference
Dealing with large data sets makes it necessary to pick out only the newest or the hottest elements ...
- 一次项目中用到的php函数总结
最近做的一个项目,我把做的过程中用到的php函数总结一下.以后遇到类似的不用百度,直接看自己总结的就好了.都是一些简单基础的函数,随手记下.方便以后学习. 1.array_sum() 返回数组中的所有 ...