生成器的本质就是迭代器。
生成器包括两种:生成器函数和生成器表达式
1.生成器函数
一个包含yield关键字的函数就是一个生成器函数。并且yield不能和return共用,并且yield只能用在函数内。
(1).生成器函数执行之后会得到一个生成器作为返回值,并不会执行函数体。
(2).执行了__next__()方法之后才会执行函数体,并且获得返回值。
(3).next()内置方法,内部调用生成器函数的__next__()方法。
(3).yield和return相同的是可以返回值,但是不同的是yield 不会结束函数
练习1:创建一个生成器,并且调用
def generator():
print('xxxx')
yield
print('zzzz')
yield
ret=generator()
print(ret) # 返回一个生成器对象,也就是一个迭代器,必须使用__next__方法才能执行函数体
ret.__next__() # 调用__next__方法执行函数体,遇到yield停止
# 也可以写成next(ret)的方式
next(ret)
# ret.__next__() # 执行前面,没有遇到yield然后报错
# next(ret) # 执行前面,没有遇到yield然后报错
运行结果:
<generator object generator at 0x0000000001E25830>
xxxx
zzzz
练习3:创建生成器,定义多个yield 值
def generator():
print('---->')
yield 1
print('---->')
yield 2
g = generator()
ret = next(g) # ---->
print(ret) # 1
ret2 = g.__next__() # ---->
print(ret2) # 2
运行结果:
---->
1
---->
2
练习4:创建生成器,生成200万桶康师傅方便面
def ksf():
for i in range(1, 2000000):
yield '正在生成第{}桶方便面'.format(i)
g=ksf()
# ret=next(g)
# print(ret) # 此种方法只会执行一次
import time
for fbm in g:
time.sleep(1)
print(fbm)
运行结果:
正在生成第1桶方便面
正在生成第2桶方便面
正在生成第3桶方便面
正在生成第4桶方便面
正在生成第5桶方便面
......
2.send()方法
send 获取下一个值的效果和next()基本一致,只是在获取下一个值的时候,给上一yield的位置传递一个数据
使用send的注意事项
(1).第一次使用生成器的时候 是用next获取下一个值
(2).最后一个yield不能接受外部的值
使用send()方法给yield传递参数
def generator():
print('aa')
content=yield 1
print(content)
print('--->')
yield 2
g=generator()
ret=next(g) # aa
print(ret) # 1
g.send('hello') # 将hello传给content
# g.send('zz') # 报错,下面没有yield来停止了
运行结果;
aa
1
hello
--->
练习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()
print(next(g))
print(g.send(10))
print(g.send(20))
print(g.send(30))
运行结果:
0
10.0
15.0
20.0
3.yield form
yield from 循环遍历容器类型
练习1:使用for循环取出g1生成器中所有的值。
普通方法:
def g1():
for i in range(3):
yield i
for j in ‘ab’:
yield j
a=g1()
print(a.next())
print(a.next())
print(a.next())
print(a.next())
print(a.next())
运行结果;
0
1
2
a
b
此种方法较为繁琐,需要从返回的迭代器中一个一个的取
使用yield form方法
def g1():
yield from range(3)
yield from 'ab'
a=g1()
for gg in g1():
print(gg)
运行结果;
0
1
2
a
b
4.生成器表达式
格式:将列表解析式[] 改成 () 即可。
练习1:使用生成器表达式,进行数数。
g=(i for i in range(10))
print(g) # 返回生成器对象
for i in g:
print(i)
运行结果:
<generator object <genexpr> at 0x0000000002175830>
0
1
2
3
4
5
6
7
8
9
使用类型转换形式遍历迭代器
def demo():
for i in range(4):
yield i
g=demo()
# 函数底层会默认调用g的__next__()方法
print(list(g)) # [0, 1, 2, 3]
运行结果:
[0, 1, 2, 3]
5.生成器作用
可以实现多任务(协程–>模拟并发)