生成器
生成器仅仅保存了一套生成数值或者对象的算法, 并且没有让这个算法现在就开始执行, 而是我什么时候调它, 它什么时候开始计算一个新的值, 并给你返回.
存储海量的数据会占用内存资源, 如果我们可以根据算法推算后面的数据, 什么时候需要的时候就去生成, 这样将极大地减少内存占用.
创建生成器
1. 列表生成式的 [] 改成()
- L = [x * x for x in range(10)]
- print(L)
- G = (x * x for x in range(10))
- print(G)
- print(next(G)
执行结果
- [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
- <generator object <genexpr> at 0x02739DB0>
- 0
next 是生成器能迭代的关键, next(G)等价于 G.__next__(), 调用他就生成一个新的对象并返回.
2. yield
在函数里面有 yield 关键字, 函数就变成了一个生成器. 当调用 next()函数时, 就相当于生成下一个对象(统称), 这一次 next 开始的地方是接着上一次 next 停止的地方执行的, 即 yield 之后继续执行, 到 yield 处返回生成的对象.
例子
- def fun():
- print('run fun')
- while True:
- rtn = yield 6
- print('rtn:',rtn)
- g = fun()
- print(g)
- print(next(g))
- print('-------')
- print(next(g))
- print('------------')
- print(next(g))
执行结果
- <generator object fun at 0x0278CDB0>
- run fun 6 ------- rtn: None 6 ------------ rtn: None 6
分析
程序开始执行以后, 因为 fun 函数中有 yield 关键字, 所以先得到一个生成器对象 g, 由 print(g)可以看出他是一个生成器对象
直到调用 next 方法, fun 函数正式开始执行, 先执行 fun 函数中的 print 方法, 然后进入 while 循环(++ 生成器都有一个 while True 循环以此不断生成对象并返回 ++)
程序遇到 yield 关键字, 把 yield 想象成 return,return 了一个 6 之后, 程序停止, 并没有执行赋值操作, 此时 next(g)语句执行完成, 返回 6, 是执行 print(next(g))的结果,
程序执行 print,, 输出 ---
又开始执行下面的 print(next(g)), 这个时候是从刚才那个 next 程序停止的地方开始执行, 也就是要执行 rtn 的赋值操作, 这时候要注意, 这个时候赋值操作的右边是没有值的(因为刚才那个是 return 出去了, 并没有给赋值操作的左边传参数), 所以这个时候 rtn 赋值是 None, 所以接着下面的输出就是 rtn:None, 继续走 while 循环
又一次碰到 yield, 这个时候同样 return 出 6, 然后程序停止, print 函数输出的 6 就是这次 return 的返回值.
继续 5-6
再看
- def fun():
- print('run fun')
- while True:
- rtn = yield 6
- print('rtn:',rtn)
- g = fun()
- print(g)
- print(next(g))
- print('-------')
- print(g.send(True))
- print('------------')
- print(g.send('赋值操作'))
执行结果
- <generator object fun at 0x029AEAB0>
- run fun 6 ------- rtn: True 6 ------------
rtn: 赋值操作
6
这次的 rtn 为什么有值了呢?
send 和 next 区别
1. send 和 next()都是让生成器向下走一次
2. send 可以给上一个 yield 的位置传递值, 不能给最后一个 yield 发送值, 在第一次执行生成器代码的时候不能使用 send()
send()干了两件事情:
发送一个参数做赋值操作
函数内部包含执行 next(),yield 6 返回
生成器
来源: http://www.bubuko.com/infodetail-3364628.html