目录
练习2:使用 yield from 遍历出可变数据类型中的数据。
练习2:list()函数底层会默认调用g的__next__()方法
生成器的本质就是迭代器。
生成器包括两种:生成器函数和生成器表达式
一、生成器函数
一个包含yield关键字的函数就是一个生成器函数。并且yield不能和return共用,并且yield只能用在函数内。
(1).生成器函数执行之后会得到一个生成器作为返回值,并不会执行函数体。
(2).执行了__next__()方法之后才会执行函数体,并且获得返回值。
(3).next()内置方法,内部调用生成器函数的__next__()方法。
(3).yield和return相同的是可以返回值,但是不同的是yield 不会结束函数
练习1:创建一个生成器,并且调用
# 1、创建一个生成器,并且调用
def generator():
print('lalala')
yield
print('hhh')
yield
g = generator()
# 注意:调用生成器,函数体是不会执行的,会返回一个生成器对象
print(g)
输出为:
<generator object generator at 0x0000000002145830>
调用__next__()方法或者是next()函数可以执行函数体。遇到yield停止
g.__next__() # 调用__next__()方法执行函数体。遇到yield停止
g.__next__()
# 或是
# next(g)
# next(g)
输出为:
lalala
hhh
练习2:创建一个生成器,并且设置返回
def generator():
print('---->>>')
yield '这是返回值'
g = generator()
ret = next(g)
print(ret)
ret变量接收返回值,然后打印
---->>>
这是返回值
练习3:创建生成器,定义多个yield 值
def generator():
print('---->')
yield 1
print('---->>>')
yield 2
g = generator()
ret = next(g)
print(ret)
ret2 = next(g)
print(ret2)
输出为:
---->
1
---->>>
2
练习4:创建生成器,生成200万桶方便面。
def ksf():
for i in range(1, 2000000):
yield '正在生产第%d桶方便面' % i
g = ksf()
print(next(g))
print(next(g))
输出为:
正在生产第1桶方便面
正在生产第2桶方便面
从上代码中我们可以发现,在yield的影响下,调动一次才运行一次。我们使用for循环试一下
for fbm in g :
print(fbm)
它就一直在输出了,如
二、send()
send 获取下一个值的效果和next()基本一致,只是在获取下一个值的时候,给上一yield的位置传递一个数据。
使用send的注意事项:
(1).第一次使用生成器的时候 是用next获取下一个值
(2).最后一个yield不能接受外部的值
练习1:使用send()方法给yield传递参数
def generator():
print('aa')
content = yield 1
print(content)
print('---->')
yield 2
g = generator()
ret=next(g)
print(ret)
g.send('hello')
输出为:
aa
1
hello
---->
1、如上代码所示,当程序运行到next(g)时,程序输出了'aa'
2、然后碰到了第一个yield,程序停止运行了,并返回了值'1',我们用ret接收了这个返回的值,然后我们print(ret),就输出了1
3、之后程序运行了g.send('hello'),把'hello'返回了第一个yidle,而我们用变量content接收了yield ‘hello',同时程序继续运行print(content),输出了'hello',然后继续下行,print('---->'),输出了---->
4、代码碰到了第二个yield,程序停止运行
练习2:计算移动平均值
def fun_avg():
count = 1
avg = 0
total = 0
while True:
get_num = yield avg
total += get_num
avg = total / count
count += 1
g=fun_avg()
next(g)
print(g.send(10))
print(g.send(20))
print(g.send(30))
输出为:
10.0
15.0
20.0
1、如上代码所示,当print(next(g))运行时,程序运行碰到了yield,返回了avg的值即'0',程序停止了,然后被print函数输出了
2、然后print(g.send(10))运行时,把'10'返回了yield,程序继续运行,所以get_num=10,total=10,avg=10,count=1+1=2,又因为在while循环里,所以程序继续从头开始走,然后碰到了yield,此时avg=10,yield返回了avg并停止了运行,被print函数输出了
3、print(g.send(20))运行时,把'20'返回了yield,程序继续运行,所以get_num=20,total=10+20=30,avg=30/2=15,count=2+1=3,然后又循环一次,碰到了yield,此时avg=15,所以yield返回了avg并停止了运行,被print函数输出
4、print(g.send(30))运行时,把'30'返回了yield,程序继续运行,所以get_num=30,total=30+30=60,avg=60/3=20,count=3+1=4,然后又循环一次,碰到了yield,此时avg=20,所以yield返回了avg并停止了运行,被print函数输出
三、yield form
yield from 循环遍历容器类型
练习1:使用for循环取出g1生成器中所有的值。
def g1():
for i in range(3):
yield i
for j in 'ab':
yield j
g = g1()
for gg in g:
print(gg)
print(list(g1()))
输出为:
0
1
2
a
b
[0, 1, 2, 'a', 'b']
如上代码所示,for循环是遍历出g1()中的值来。
而print(list(g1()))则是直接将g1()中的值赋值到列表中。
练习2:使用 yield from 遍历出可变数据类型中的数据。
def g1():
yield from range(3)
yield from 'ab'
g = g1()
for gg in g:
print(gg)
print(list(g1()))
四、生成器表达式
格式:将列表推导式[] 改成 () 即可。
练习1:使用生成器表达式,进行数数。
g=(i for i in range(10))
print(g)
for j in g:
print(j,end=' ')
输出为:
<generator object <genexpr> at 0x0000000001DF58E0>
0 1 2 3 4 5 6 7 8 9
练习2:list()函数底层会默认调用g的__next__()方法
def demo():
for i in range(4):
yield i
g = demo()
# list()函数底层会默认调用g的__next__()方法
print(list(g))
输出为:
[0, 1, 2, 3]
五、生成器作用
可以实现多任务(协程-->模拟并发)