17. 生成器
1. 概述
元组推导式是生成器(generator)
生成器本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑
生成器可以用两种方式创建:
(1)生成器表达式 (里面是推导式,外面用圆括号)
(2)生成器函数 (用def定义,里面含有yield)
2. 生成器的基本用法
生成器表达式
gen = ( i for i in range(5))
print(gen,type(gen))

生成器中获取数据的方式
for循环
gen = ( i for i in range(5))
for i in gen:
print(i)
next调用
gen = ( i for i in range(5))
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
for循环和next配合调用生成器中的数据
gen = ( i for i in range(5))
for i in range(5):
res = next(gen)
print(res)
3. 生成器函数
yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
而return直接终止函数,每次重头调用.
生成器函数基本用法
def mygen():
print("one")
yield 1
print("two")
yield 2
print("three")
yield 3
初始化生成器函数 返回生成器对象, 简称生成器
gen = mygen()
print(isinstance(gen,Iterator))
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
# res = next(gen) error 越界错误
# print(res)
上述代码解析
代码解析:
通过next调用生成器对象,找到mygen函数,代码依次从上到下执行:
先走12行 print("one") yield 1 记录当前执行代码的位置状态 , 添加阻塞 ,把1直接返回,等待下一次调用
在通过next进行调用时,
从上一次记录的那个位置状态往下走,
print("two") yield 2 记录当前执行代码的位置状态 , 添加阻塞 ,把2直接返回,等待下一次调用
在通过next进行调用时,
从上一次记录的那个位置状态往下走,
print("three") yield 3 记录当前执行代码的位置状态 , 添加阻塞 ,把3直接返回,等待下一次调用
在通过next进行调用时,
从上一次记录的那个位置状态往下走,发现已经没有yield,直接越界报错.
send
不但可以获取值,还能发送值,发送给上一个yield
next和send区别:
next 只能取值
send 不但能取值,还能发送值
send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接收不到send的发送值
示例说明
def mygen():
print("program start")
res = yield 1
print(res)
res = yield 2
print(res)
res = yield 3
print(res)
print("program end")
# 初始化生成器函数 => 变成生成器对象 简称 生成器
print("<===================>")
gen = mygen()
res2 = gen.send(None)
print(res2)
res2 = gen.send(1111)
print(res2)
res2 = gen.send(2222)
print(res2)

代码解析
代码解析:
res = gen.send(None) 第一次通过send 调用时,因为send 默认发送给上一个yield,所以第一次发送不了,只能默认发送None,属于硬性语法
第一次代码调用时,只走到了3行 ,记录代码执行的位置状态,添加阻塞,返回值1
在调用时,通过send(1111)给yield 1 res 接收到了send发送过来的返回值 , 生成器函数中从上一次代码记录的位置,往下走,走4行代码,打印 1111
继续执行5行代码, 把yield 2返回,记录代码执行的位置状态,添加阻塞,返回值2
在调用时,通过send(2222)给yield 2 res 接收到了send发送过来的返回值 , 生成器函数中从上一次代码记录的位置,往下走,走6行代码,打印 2222
继续执行7行代码, 把yield 3返回,记录代码执行的位置状态,添加阻塞,返回值3
在调用时,通过send(3333)给yield 3 res 接收到了send发送过来的返回值 , 生成器函数中从上一次代码记录的位置,往下走,走85行代码,打印 3333
问题是再也没有yield 响应的返回了,直接报错.
yield from : 将一个可迭代对象变成一个迭代器返回
系统默认会把from后面的可迭代性数据,每个元素扔到迭代器中,通过next一个一个调用
def mygen():
yield from ["张三","李四","王五","大刀"]
gen = mygen()
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
res = next(gen)
print(res)
