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

通过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. 转载:Cocos2D-x 游戏接入 Windows 设备所需做的六件事

    原文地址:http://msopentech.com/zh-hans/blog/2014/05/09/cocos2d-x-%E6%B8%B8%E6%88%8F%E6%8E%A5%E5%85%A5-wi ...

  2. CODESOFT都出中文官网了,你还等什么呢

    CODESOFT是先进的标签设计和集成软件,提供了无与伦比的灵活性.功能和世界范围的支持,是企业环境下标签打印的最佳选择.在过去的时间里,CODESOFT从未停止过努力与改进,现如今已推出了最新版本C ...

  3. Flex应用一览表

    1.Flex控件之repeater和radioButton控件应用 2.Flex之DataGrid和Tree控件的数据源XML格式  3.Flex控件之combobox应用 4.转:Flex的Arra ...

  4. How to deploy JAVA Application on Azure Service Fabric

    At this moment, Azure Service Fabric does not support JAVA application natively (but it's on the sup ...

  5. 对.Net系统架构改造的一点经验和教训

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 在互联网行业,基于Unix/Linux的网站系统架构毫无疑问是当今主流的架构解决方案 ...

  6. 第1章 shell编程概述

    1.shell简介 shell是一种具备特殊功能的程序,它提供了用户与内核交互操作的一种接口.它用于接收用户输入的命令,并把它送入到内核去执行. shell是一种应用程序,当用户登录Linux系统时, ...

  7. 简单JS实现对表的行的增删

    这段代码非常的简单,仅仅作为自己的一个小小的记录! ok,先上一个简单的图例,效果如下(注意:这只是一个简单的例子,不过可以根据这个简单的例子,变化出更为复杂的效果)! 代码也非常的简单,如下所示(注 ...

  8. ASPxGridView的自动排序(写在onCustomUnboundColumnData()事件中)

    //此排序写于后台,可打印出序号 protected void ASPxGridView_progoods_CustomUnboundColumnData(object sender, DevExpr ...

  9. WP_3种磁贴效果设置

    private void ApplicationBarIconButton_Click_1(object sender, EventArgs e) { var tileData = new FlipT ...

  10. JS常用的设计模式(14)—— 备忘录模式

    备忘录模式在js中经常用于数据缓存. 比如一个分页控件, 从服务器获得某一页的数据后可以存入缓存.以后再翻回这一页的时候,可以直接使用缓存里的数据而无需再次请求服务器. 实现比较简单,伪代码: var ...