1. 什么是生成器

  通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且, 创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后 面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否 可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。

在 Python中,这种一边循环一边计算的机制,称为生成器:generator。

2. 创建生成器方法1

要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )

#列表生成式(列表推导式)
l = [i for i in range(0,10,2)]
print(l)
# 生成器
g = (i for i in range(0,10,2))
print(g)

结果为:

[0, 2, 4, 6, 8]
<generator object <genexpr> at 0x00000000029B2BF8>

创建 L 和 G 的区别仅在于最外层的 [ ] 和 ( ) , L 是一个列表,而 G 是一个生成器。我们可以直接打印 出L的每一个元素,但我们怎么打印出G的每一个元素呢?如果要一个一个打印出来,可以通过 next() 函数 获得生成器的下一个返回值:

print(next(g)) # 0
print(next(g)) # 2
print(next(g)) # 4
print(next(g)) # 6
print(next(g)) # 8
print(next(g)) # StopIteration

生成器保存的是算法,每次调用 next(G) ,就计算出 G 的下一个元素的值,直到计算到最后一个元素, 没有更多的元素时,抛出 StopIteration 的异常。

可以使用 for循环取出每个元素,这样就不会报错,

for i in g: # g是一个生成器,可以直接循环
print(i)

结果为: 这样也不用担心会取不到值而报错

0
2
4
6
8

3.创建生成器方法2

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以 用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加 得到: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... 斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(times):
a = 0
b = 1
n = 1
while n<=times:
print(b)
a,b = b,a+b
n+=1
fib(7)

结果为:

1
1
2
3
5

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算 出后续任意的元素,这种逻辑其实非常类似generator。 也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就 可以了:

#生成器写法
def fib(times):
a = 0
b = 1
n = 1
while n<=times:
#print(b)
yield b
a,b = b,a+b
n+=1
return "done!"

简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普 通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一 个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的 本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。 同样的,把函数改成generator后,我们基本上从来不会用 next() 来获取下一个返回值,而是直接使用 for 循环来迭代:

for i in F:
print(i) #结果与上面相同

但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值, 必须捕获StopIteration错误,返回值包含在StopIteration的value中:

while True:
try:
print(next(F))
except StopIteration as e:
print("生成器返回值:%s"%e.value)
break

总结:

生成器是这样一个函数,它记住上一次返回时在函数体中的位置。

对生成器函数的第二次(或第 n 次) 调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。

生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只 是数据值)中的位置。

生成器的特点:

1. 节约内存

2. 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参 数都是第一次所调用时保留的,而不是新创建的

生成器(generator)的更多相关文章

  1. Python复习之生成器 generator

    生成器 generator def h(): print "hello" m = yield 5 print "m:", m d = yield 12 prin ...

  2. 生成器(generator)内部解析

    #http://kb.cnblogs.com/page/87128/(未看完)

  3. 生成器generator

    生成器generator 定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器 代码: def cash_out(a ...

  4. ES6中的迭代器(Iterator)和生成器(Generator)

    前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简 ...

  5. Hibernate中的主键生成器generator

    本文讲述Hibernate的generator属性的意义.Generator属性有7种class,本文简略描述了这7种class的意义和用法. [xhtml] view plaincopy <c ...

  6. Python进阶内容(四)--- 迭代器(Iterator)与生成器(Generator)

    迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的ge ...

  7. 廖雪峰老师博客学习《通过生成器generator生成列表式杨辉三角》

    说明:这是我接触生成器概念后,自己对它的理解,可能比较表面,没深入理解,也可能有错误.后续校正错误认知,将有关generator作为一个tag了! 希望以后能活用. 先贴出自己写的triangles( ...

  8. 003_生成器(generator)内部解析

    #http://kb.cnblogs.com/page/87128/(未看完)

  9. Python之生成器(generator)和迭代器(Iterator)

    generator 生成器generator:一边循环一边计算的机制. 生成器是一个特殊的程序,可以被用于控制循环的迭代行为.python中的生成器是迭代器的一种,使用yield返回值函数,每次调用y ...

  10. Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍

    原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...

随机推荐

  1. 使用tf.print()打印tensor内容

    使用tf.Print()打印tensor内容,这是tensorflow中调试bug的一个手段,例子如下所示: import tensorflow as tf a = tf.Variable(tf.ra ...

  2. poj2480-Longge's problem-(欧拉函数)

    Longge is good at mathematics and he likes to think about hard mathematical problems which will be s ...

  3. AngularJS 中{{}}与ng-bind指令

    面试中,有被问题关于{{}}与ng-bind指令的问题,在此,分享下自己的知识点. 在脚本没有加载完成时,用户会看到{{}},界面比较丑陋.     一般的解决方法: 在index.html里面使用n ...

  4. node.js fs、http使用

    学习node核心模块http.fs;的使用 首先在server.js文件中require两个模块http.fs; let fs = require('fs')let http = require (' ...

  5. 03_java基础(二)之jdk的安装与环境变量配置

    1.语言与机器语言 语言 : 通常说的语言其实就是人与人之间沟通的一种方式计算机编程语言: 可以看成是人与计算机之间交流的一种方式 C,C++,C#,PHP,Java等 2.Java语言的历史 是SU ...

  6. JUC(java.util.concurrent)

    在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池.异步 IO 和轻 ...

  7. 1.3.5、CDH 搭建Hadoop在安装之前(端口---Cloudera Search使用的端口)

    Cloudera Search使用的端口 在下表中,每个端口的“ 访问要求”列通常是“内部”或“外部”.在此上下文中,“内部”表示端口仅用于组件之间的通信; “外部”表示该端口可用于内部或外部通信. ...

  8. Avatar

    [Avatar] 1.Retargeting of Humanoid animations Retargeting is only possible for humanoid models, wher ...

  9. JXS In Depth

    [JXS In Depth] 1.Spread Attributes If you already have props as an object, and you want to pass it i ...

  10. lvm磁盘分区

    初始分区情况见下: 创建lvm类型磁盘 创建卷pv 添加pv到vg中,vg名vgroup0 创建lv lvcreate -L 2g -n zookeeper vgroup0 在vg vgroup0中创 ...