生成器是一种暂缓求值的技术,它可以用来生成一系列的值,但不会一次性生成所有的值,而只在需要的时候才计算和生成一个值。

通过yield语句构建生成器

要得到一个生成器,我们需要定义一个函数,这个函数返回一个生成器。这个函数与普通函数不同的地方在于,它使用 yield 来返回值。

下面这个函数返回一个生成器,该生成器用来产生斐波拉契数:

# fib函数返回一个生成器
def fib(max):
a, b = 0, 1
while a < max:
yield a
a, b = b, a + b g = fib(10) # 此时斐波拉契数列还没有生成
# 每次调用生成器的next()方法,就计算下一个要返回的斐波拉契数
print g.next()
print g.next()
print g.next()
print g.next() # 可以在循环中使用生成器
for f in fib(10):
print f

yield语句用来返回当前的值,然后退出函数。生成器会记住当前的状态,当下次调用next()方法的时候,会从上次的状态开始,直到yield返回一个新的值。

一些内置函数以及Python的某些语句能够接受一个生成器,在需要的时候调用它的next()方法。

例如 for...in 语句:

for f in fib(100):
print f

又比如内置的list()函数,可以接受一个生成器来得到一个新列表:

L = list(fib(100))

你当然也可以定义自己的函数,接受一个生成器,在函数内部调用这个生成器的next()方法获取它的值。

生成器表达式

如果觉得每次都要定义函数来返回生成器有点麻烦,那么 生成器表达式 能够让你仅用一个表达式就能得到一个生成器。

>>> g = (i for i in range(10)) # 生成器表达式
>>> g
<generator object <genexpr> at 0x103814410>

上面在两个括号中使用了类似循环的表达式,我们把这种括号语法叫生成器字面量,而括号里的表达式也就是生成器表达式。后面有更多各种字面量的介绍。

生成器表达式适合用在比较简单的情形下,就跟我们需要lambda表达式来快捷得到一个匿名函数一样。

生成器表达式是如此方便,它的适用范围绝不只是在字面量中,它可以直接作为函数的参数,这点在下面会讲到。

为什么使用生成器

生成器只有在每次调用它的next()方法的时候,才计算以及返回下一个值,这有利于节省内存空间。

例如要处理一个从0到9999的数据集合,我们可以先用range函数得到一个0到9999的列表,然后遍历这个列表逐个处理每个数字,但这样的话,直到我们处理完,这个长度为10000的列表会一直驻留在我们的内存中;但如果使用生成器,只有在每次处理的时候才会让生成器产生一个值,这显然有利于内存利用。

# 使用列表
L = [i for i in range(10000)]
for i in L:
print i # 使用生成器
g = (i for i in range(10000))
for f in g:
print f

生成器表达式和列表综合

  1. 生成器表达式使用括号,而列表综合使用中括号。

    >>> g = (i for i in range(10)) # 生成器表达式
    >>> g
    <generator object <genexpr> at 0x103814410>
    >>> L = [i for i in range(10)] # 列表综合表达式
    >>> L
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>s1 = {i for i in range(10)} # 集合综合
    >>s1
    >>set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
  2. 列表综合只用在字面量表达式里,生成器表达式却可以作为函数参数。

        >>s2 = set(i for i in range(10))
    >>s2
    >>set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

set()是一个内置函数,i for i in range(10)是生成器表达式,它返回一个生成器来作为 set 函数的实参。为了证明是返回了一个生成器,我们定义一个函数 get_set(),

>>> def get_set(g):
print repr(g)
print set(g)
>>get_set(i for i in range(10))
<generator object <genexpr> at 0x103914460>
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

我们在get_set函数中打印参数g,我们可以看到g确实是一个生成器。

更多字面量

其他语言(Java,C#)中都有字面量这个术语,其实Python中也可以使用这个术语,例如下面这些都可以叫做字面量:

  • 字符串字面量,用引号表示,我们经常用这种方法来创建一个字符串。

    s = '用字面量语法表示一个字符串'

  • 列表字面量,用中括号表示。

    L1 = [0,1,2,3,4]
    L2 = [i for i in range(5)] # 使用了列表综合语法

  • 集合字面量,用花括号表示。

    set1 = {0,1,2,3,4}
    set2 = {i for i in range(5)} # 集合综合语法

  • 字典字面量,也用花括号表示,但语法与集合不同。

    d = {1: 'a', 2: 'b', 3: 'c'}

  • 生成器字面量,用括号表示,需要借助生成器表达式。

    g = (i for i in range(10))

Python生成器以及yield语句的更多相关文章

  1. Python中生成器和yield语句的用法详解

    Python中生成器和yield语句的用法详解 在开始课程之前,我要求学生们填写一份调查表,这个调查表反映了它们对Python中一些概念的理解情况.一些话题("if/else控制流" ...

  2. 生成器以及yield语句

    生成器以及yield语句最初的引入是为了让程序员可以更简单的编写用来产生值的序列的代码. 以前,要实现类似随机数生成器的东西,需要实现一个类或者一个模块,在生成数据的同时 保持对每次调用之间状态的跟踪 ...

  3. Python生成器与yield

    列表推导与生成器表达式 当我们创建了一个列表的时候,就创建了一个可以迭代的对象: >>> squares=[n*n for n in range(3)] >>> f ...

  4. Python生成器(yield)

    对于调用一个普通的Python函数,一般是从函数的第一行代码开始执行,结束于return语句.异常或者函数所有语句执行完毕.一旦函数将控制权交还给调用者,就意味着全部结束.函数中做的所有工作以及保存在 ...

  5. python生成器中yield和send分析

    生成器 在python中生成器是指用代码实现迭代器的的功能本质还是迭代器,只不过是代码实现迭代器功能.在python中生成器是由函数实现的,通常我们在函数中加入yeild就可以实现生成器. 生成器中y ...

  6. Python中的yield和Generators(生成器)

    本文目的 解释yield关键字到底是什么,为什么它是有用的,以及如何来使用它. 协程与子例程 我们调用一个普通的Python函数时,一般是从函数的第一行代码开始执行,结束于return语句.异常或者函 ...

  7. python 生成器 迭代器

    阅读目录 一 递归和迭代 二 什么是迭代器协议 三 python中强大的for循环机制 四 为何要有for循环 五 生成器初探 六 生成器函数 七 生成器表达式和列表解析 八 生成器总结 一 递归和迭 ...

  8. python -迭代器与生成器 以及 iterable(可迭代对象)、yield语句

    我刚开始学习编程没多久,对于很多知识还完全不知道,而有些知道的也是一知半解,我想把学习到的知识记录下来,一是弥补记忆力差的毛病,二也是为了待以后知识能进一步理解透彻时再回来做一个补充. 参考链接: 完 ...

  9. python 生成器 yield语句

    生成器就是一个返回迭代器(iterator)的函数. 包含了 yield 的函数,就是一个生成器. 生成器每使用yield语句产生一个值,函数就会被冻结(暂停执行),被唤醒后(即再次调用)接着上次执行 ...

随机推荐

  1. MacPE+WinPE-黑苹果之路

    装黑苹果过程中,安装.备份.恢复都需要启动到MAC,总是从硬盘启动对于硬盘数据风险太大,琢磨着安装个pe用来维护,此外手上的winpe,也想着一并实现,免得搞两个u盘.找了个网页开工,http://b ...

  2. 下一代大数据系统和4S标准

    大数据行业发展到今天,它创造的价值和带来的社会效应,大家已经看得很明白,同时很多问题和不足也暴露出来,特别是hadoop能够提供的数据处理能力,现在已经挖掘到极限,但是现在各行业对数据的存储和计算需求 ...

  3. 将tomcat设为开机自动启动

    参考网址:http://jingyan.baidu.com/article/a65957f4b12b8724e77f9b5a.html 方法一 1.Tomcat的使用之前必须得Jre,至于是怎么装的, ...

  4. ZigBee无线网络技术在小区路灯照明系统的应用

    小区路灯照明系统是楼宇智能的一部分,但受制于布线.成本等的问题,难以得以实施.随着计算机技术的迅猛发展,无线网络技术越来越成熟,ZigBee无线网络成本低.功耗低.传输距离远等的特点,非常适合在无线路 ...

  5. 对于不是特别擅长Photoshop的人来说,熟悉和运用Photoshop工具提供的各类便捷的快捷键,是有帮助的。

    应用程序菜单快捷键之文件   应用程序菜单快捷键之编辑   应用程序菜单快捷键之图像图层   应用程序菜单快捷键   应用程序菜单快捷键之视图     Ctrl + H  取消参考线     调板菜单 ...

  6. XSS CSRF 攻击

    XSS:跨站脚本(Cross-site scripting) CSRF:跨站请求伪造(Cross-site request forgery)定义: 跨网站脚本(Cross-site scripting ...

  7. Easyui扩展或者重载(方法和属性)

    1: 使用$.fn.datagrid.defaults.editors重载默认值. 每个编辑器都有以下方法: 名称 属性 描述 init container, options 初始化编辑器并返回目标对 ...

  8. gdb调试工具使用方法分享

    刚才看了一个CSDN上分享gdb调试工具使用的教程,讲得非常好,推荐到这里: http://blog.csdn.net/liigo/article/details/582231

  9. Button的图像位置设置

    [button setImageEdgeInsets:UIEdgeInsetsMake(2, 70, 2,70 )]; [button setImageEdgeInsets:UIEdgeInsetsM ...

  10. ASP.NET MVC SignalR(1):背景

    系列目录:ASP.NET MVC SignalR 关键词:HTTP.轮询.WebSocket.Server-Sent Events.长轮询.forever frame. 1. HTTP HTTP(Hy ...