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. Java7/8 HashMap ConcurrentHashMap

    网上关于 HashMap 和 ConcurrentHashMap 的文章确实不少,不过缺斤少两的文章比较多,所以才想自己也写一篇,把细节说清楚说透,尤其像 Java8 中的 ConcurrentHas ...

  2. common mistake of closure in loops

    [common mistake of closure in loops] 下例中item引用的始终是最后一个值. function showHelp(help) { document.getEleme ...

  3. JMeter学习(九)FTP测试计划(转载)

    转载自 http://www.cnblogs.com/yangxia-test FTP服务主要提供上传和下载功能.有时间需要我们测试服务器上传和下载的性能.在这里我通过JMeter做一个FTP测试计划 ...

  4. python学习 day19 configparser模块 os模块 subprocess模块

    上周五回顾 logging 用于记录日志 四种核心角色: 生成器Logger 过滤器Filter 处理器Handler 格式化处理器 Formatter logging.info.debug 使用默认 ...

  5. div 绑定keyup

    参考 https://www.cnblogs.com/Struts-pring/p/4290740.html <div tabindex="-1" onkeyup=" ...

  6. 第二章 向量(d1)有序向量:唯一化

  7. Django项目之客户

    关于客户的操作 主页(被继承) {% load static %} <!DOCTYPE html> <html lang="en"> <head> ...

  8. Node使用 Express框架,实现文件上传

    一 安装依赖包 npm install multer --save 二 客户端上传文件 <!DOCTYPE html> <html> <head> <meta ...

  9. crm作业知识点集合[三]

    知识点1 我们要实现一个这样的功能,在学生表中,可以查看每个学生的报名的班级的所有的成绩,就是下图的效果 1.首先我们需要在学生表中自定义一列,这一列的内容就是一个a标签,指向另外一个页面,而我们在另 ...

  10. fnb2b分支拉取注意事项

    1. 大B分支拉取以后不要忘记把index.php中dev环境改为 $save_url = "http://dev-b2b.dev1.fn/"; 2. 大B分支拉取后,记得/bas ...