生成器(generator)
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)的更多相关文章
- Python复习之生成器 generator
生成器 generator def h(): print "hello" m = yield 5 print "m:", m d = yield 12 prin ...
- 生成器(generator)内部解析
#http://kb.cnblogs.com/page/87128/(未看完)
- 生成器generator
生成器generator 定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器 代码: def cash_out(a ...
- ES6中的迭代器(Iterator)和生成器(Generator)
前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简 ...
- Hibernate中的主键生成器generator
本文讲述Hibernate的generator属性的意义.Generator属性有7种class,本文简略描述了这7种class的意义和用法. [xhtml] view plaincopy <c ...
- Python进阶内容(四)--- 迭代器(Iterator)与生成器(Generator)
迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的ge ...
- 廖雪峰老师博客学习《通过生成器generator生成列表式杨辉三角》
说明:这是我接触生成器概念后,自己对它的理解,可能比较表面,没深入理解,也可能有错误.后续校正错误认知,将有关generator作为一个tag了! 希望以后能活用. 先贴出自己写的triangles( ...
- 003_生成器(generator)内部解析
#http://kb.cnblogs.com/page/87128/(未看完)
- Python之生成器(generator)和迭代器(Iterator)
generator 生成器generator:一边循环一边计算的机制. 生成器是一个特殊的程序,可以被用于控制循环的迭代行为.python中的生成器是迭代器的一种,使用yield返回值函数,每次调用y ...
- Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍
原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...
随机推荐
- pandas.read_csv用法(转)
的数据结构DataFrame,几乎可以对数据进行任何你想要的操作. 由于现实世界中数据源的格式非常多,pandas也支持了不同数据格式的导入方法,本文介绍pandas如何从csv文件中导入数据. 从上 ...
- atrous convolution
atrous convolution 简而言之,带孔卷积: 来自:https://zhuanlan.zhihu.com/p/27470685 假设一个二维信号,每个位置对应的输出为和卷积核为,带孔卷积 ...
- 如何自学web安全(详细路径)
看到学习路径,收藏一下https://blog.csdn.net/q251500/article/details/79441316
- 在Laravel外独立使用laravel-mongodb
laravel框架外部使用laravel-mongodb 插件 下载安装方式主要根据github上的参考: https://github.com/jenssegers/laravel-mongodb# ...
- Spread Syntax
[Spread Syntax] The spread syntax allows an expression to be expanded in places where multiple argum ...
- appium+python自动化测试
appium+python自动化测试 标签(空格分隔): appium 获取APP的包名 1.aapt即Android Asset Packaging Tool,在SDK的build-tools目录下 ...
- ss源码学习--从协议建立到完成一次代理请求
上一次介绍了ss源码中各个事件处理函数完成的工作,这次具体分析一下协议的建立以及请求数据的传输过程. 因为ss的local和server共用一个类以及一系列的事件处理函数,所以看起来稍显复杂.下面来将 ...
- NumPy 高级索引
NumPy 高级索引 NumPy 比一般的 Python 序列提供更多的索引方式.除了之前看到的用整数和切片的索引外,数组可以由整数数组索引.布尔索引及花式索引. 整数数组索引 以下实例获取数组中(0 ...
- Codeforces977D ---Divide by three, multiply by two 深搜+map存出现的数
传送门:点我 题意:给定n长度的序列,重排成后一个数是前一个数除以三,或者后一个数是前一个数乘二,要求输出这个序列. 思路:大力深搜,对每个数搜除3的和乘2的是否出现过,然后继续搜下去.如果有一个数搜 ...
- vue router返回上一页
this.$router.go(-1) 不用router时,使用window.history.go(-1);