python使用yield来减少内存开销
2016-01-17 15:58
405 查看
本文参考自:http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/
以斐波那契数列的实现来说明这个问题:
demo1:
但是如果max是1000w或者更大呢,那么存储在list中将会占据很大的内存。常见的情况还包括一下消耗大量内存的做法:
然后继续我们的斐波那契数列:
demo2:
上面这个版本基本达到了我们的要求,实现基本功能+节省内存,利用函数next来实现每次输出下一个值, 但是这么小小的一个功能我们竟然写了这么多的代码,不够简洁!!!
demo3:
简单来讲:yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到
yield。(照抄的参考文章)
个人理解: 是不是就是实时调用的意思,什么时候执行next什么时候执行一次fab函数,但是上一次的值都在内存中存储。而不是一次将所有的结果求出放在list中。
更多细节请参考本文一开头给出的文章链接, 下面我再补充一下关于迭代器和生成器的理解:
生成器:生成器(Generator)是创建迭代器的简单而强大的工具
迭代器:
1、对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式
2、它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。
具体的理解以及内部是如何工作的,大体可以参照:http://www.jb51.net/article/73939.htm
如果想更身体的了解迭代协议等内容,可以自行学习。
以斐波那契数列的实现来说明这个问题:
demo1:
def fab(max): n, a, b = 0, 0, 1 L = [] while n < max: L.append(b) a, b = b, a + b n = n + 1 return L for n in fab(5): print n一般来讲,我们都会写成上边程序的样子,这样既实现了基本功能,又可以复用,基本符合要求了。
但是如果max是1000w或者更大呢,那么存储在list中将会占据很大的内存。常见的情况还包括一下消耗大量内存的做法:
for line in open("test.txt").readlines(): print line #这种做法是将文件的中的内容一次全部读取到内存中,每次从内存中取出一行然后输出,如果文件内容太大,将消耗大量的内存。 for line in open("test.txt"): print line #这种做好就好多了,既简单又不节省内存,利用迭代器来每次读取一行数据。 for i in range(1000): pass #会产生一个1000个元素的list for i in xrange(1000): pass #xrange()产生的是一个迭代对象,而不是一个1000个元素的list, 每次迭代返回下一个数值上面两个小对比,是我们平时写程序时不是很注意的地方,但是当你读到这之后,以后写程序不光要考虑怎么实现,而且要写出更优秀的代码来。
然后继续我们的斐波那契数列:
demo2:
class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration() <pre class="displaycode">for n in Fab(5): print n
上面这个版本基本达到了我们的要求,实现基本功能+节省内存,利用函数next来实现每次输出下一个值, 但是这么小小的一个功能我们竟然写了这么多的代码,不够简洁!!!
demo3:
def fab(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 <pre name="code" class="python"><pre class="displaycode">for n in fab(5): print n
简单来讲:yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到
yield。(照抄的参考文章)
个人理解: 是不是就是实时调用的意思,什么时候执行next什么时候执行一次fab函数,但是上一次的值都在内存中存储。而不是一次将所有的结果求出放在list中。
更多细节请参考本文一开头给出的文章链接, 下面我再补充一下关于迭代器和生成器的理解:
生成器:生成器(Generator)是创建迭代器的简单而强大的工具
迭代器:
1、对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式
2、它不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。
具体的理解以及内部是如何工作的,大体可以参照:http://www.jb51.net/article/73939.htm
如果想更身体的了解迭代协议等内容,可以自行学习。
相关文章推荐
- python—面向对象编程
- 使用Python Pandas处理亿级数据
- 安装pip ---python windows
- 线性回归及其Python实现(最大似然法)
- Python+django实现文件下载
- VS2010中嵌入python
- Python+django实现文件上传
- python多线程的用法之一
- 【Python学习笔记】-利用MySQLdb操作mysql数据库
- 我的Python成长之路---GitHub使用克隆GitHub(SSH key配置)
- 我的Python成长之路---GitHub使用之注册GitHub并安装Git客户端
- 我的Python成长之路---第三天---Python基础(9)---2016年1月16日(雾霾)
- 我的Python成长之路---第三天---Python基础(10)---2016年1月16日(雾霾)
- python学习笔记三之文件操作(基础篇)
- Python Numpy 数组的初始化和基本操作
- [Leetcode]43. Multiply Strings @python
- 升级python之后不能使用yum?
- [Leetcode]36. Valid Sudoku@python
- 《Python for kids》学习笔记(一)
- Python对字符串的操作总结,适用于python2和python3