python生成器小结
来源:互联网 发布:网络高级工程师认证 编辑:程序博客网 时间:2024/06/08 03:41
引入及概念
通过列表生成式,我们可以直接创建一个列表。但是,受内存限制,列表的容量也是有限的,当我们创建一个包含100W个元素的列表,不仅占用内存空间比较多,而且假如我们只需要访问前几个元素,那么后面绝大部分元素占用的空间都浪费了。
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环使用的过程中不断推算后续的元素呢,这样就不必创建完整的list,浪费空间。
在python中,这种一边循环一遍计算的机制,称为生成器(Generator)。
生成器创建方式
创建方式一
首先,来看一下列表的创建:
L = [x for x in range(8)]print(L)
参照上面代码,只要做如下改动,就创建一个生成器:
# 01. 将列表生成式中的[]改为()G = (x for x in range(3))print(G)
打印结果为:
<generator object <genexpr> at 0x102967ca8>
如上,就创建了一个生成器对象。
直接打印G相当于输出的是对象地址,那么该如何取其中的元素呢?
取值方式一
通过next(G)或G.next()方式进行取值
# 打印G的值,通过next()函数 获取生成器的下一个返回值print(G.__next__())print(next(G))print(next(G))print(next(G))print(next(G))
输出为:
012Traceback (most recent call last): File "/Users/***/Project/PycharmProjects/**/generator_test.py", line 11, in <module> print(next(G))StopIteration
可以看到,这样可以取到生成器的值,不过当角标越界后,会跑出StopIteration异常,可以通过监听次异常来完成取值。
try: print(G.__next__()) print(next(G)) print(next(G)) print(next(G))except StopIteration as e: print('取值完成')
输出为:
012取值完成
取值方式二
通过for循环完成取值
for x in G: print(x)
同样可以完成对G的取值
创建方式二
只要函数中有yield关键字,该函数就不是普通函数了,而是一个生成器对象。如果再通过函数名直接调用,是无效的。
def create_num2(number): a, b = 0, 1 for x in range(number): yield b a, b = b, a + b
生成器的执行流程
通过代码,看一下生成器的调用过程。
def create_num2(number): print('create_num2 start') a, b = 0, 1 for x in range(number): # 遇到yield程序暂停,同时把后面的值返回 # 如果再次用next()进行调用,就会从上次yiled暂停的地方继续执行 print('....1....') yield b print('....2....') a, b = b, a + b print('....3....') print('create_num2 stop')a = create_num2(10)print('*' * 10 + '第一次调用yiled对象' + '*' * 10)print(next(a))print('*' * 10 + '第二次调用yiled对象' + '*' * 10)print(next(a))
输出结果为:
**********第一次调用yiled对象**********create_num2 start....1....1**********第二次调用yiled对象**********....2........3........1....1
执行流程:
1. 执行 a = create_num2(10),创建生成器对象a
2. 当调用next(a)的时候,才会执行到函数中,依次打印 start …1…
3. 当执行到yield b时,会将程序暂停,同时把后面的值(b)返回
4. 接收b的返回,此时为1,so 打印1
5. 再次执行next(a)的时候,会从上次yield暂停的地方继续执行,所以先打印…2… …3…,然后再次进入for循环,打印…1…,又遇到yield,暂停中,同时返回b的值
6. 接收b的值,并打印
使用send
在调用生成器函数时,也可以对其进行传值,如下:
# 定义一个yield对象,并且增加temp = yield idef test(): i = 0 while i < 5: temp = yield i print(temp) i += 1t = test()# 首次调用print(t.__next__())# 第二次调用print(t.__next__())# 第三次调用print(t.send('python'))
输出为:
0None1python2
执行流程:
1. 首次调用,因为temp = yield i为赋值语句,先执行右边代码,当执行到yield时,暂停执行,并把i返回回去,so ,打印 0
2. 第二次调用,从yield i开始,可以把yiedl i作为一个代码块,赋值给temp,此时没传值,所以打印为None,其他正常执行
3. 第三次调用,通过send方法,传递参数,这时候相当于把参数赋值给temp,所以打印结果为python,其他流程正常执行
ps:在第一次调用生成器的时候不能传参,否则会跑出异常,如下:
TypeError: can't send non-None value to a just-started generator
首次必须先调用next()或send(None)。
总结
- 生成器是这样一个函数,它记住上一次返回时函数体中的位置。对生成器的第二次(n)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变
- 生成器特点
- 节约内存
- 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,也就是说,在整个所有函数调用的参数都是第一次调用时保留的,而不是新创建的。
- python生成器小结
- Python 生成器
- Python生成器
- python生成器
- python 生成器
- python生成器
- python生成器
- python生成器
- python生成器
- python 生成器
- python生成器
- python 生成器
- python生成器
- python 生成器
- Python--生成器
- python 生成器
- Python 生成器
- python-生成器
- ThreadLocal使用
- docker问题汇总
- 使用Mockito进行单元测试【1】——mock and verify
- 数十种TensorFlow实现案例汇集:代码+笔记
- esriControlsMousePointer
- python生成器小结
- 657
- 爬虫入门五(Phantomjs和selenium)
- ThinkPHP 导出数据到Execel文件中
- Spring七大模块之Core
- Oracle数据泵-schema导入导出
- 关于大端模式(big-endian)与小端模式(little-endian)
- 如何使用python+selenium向富文本编辑器输入内容
- RNN详解