一.什么是生成器 (generator)
- 生成器就是一个自定义的迭代器
- 函数体内含有 yield 关键字
二.为何要使用生成器
- 为了节省内存
三.创建生成器的两种方式
- 调用带 yield 关键字的函数
- 使用生成器表达式
四. yield 关键字
- 函数体内但凡出现 yield 关键字
- 调用函数将不会触发函数体代码的运行
- 而是会返回一个生成器对象,生成器本质就是一个迭代器
def chicken():
print('=====>first')
yield 1
print('=====>sencond')
yield 2
print('=====>third')
yield 3
obj=chicken()
print(obj) # <generator object chicken at 0x000002CEE1A7AAC8> 是一个生成器, 一只老母鸡
- 生成器本质就是迭代器,也就是说生成器的玩法其实就是迭代器的玩法
print(obj.__iter__() is obj) # True
print(next(obj)) # =====>first 1
print(next(obj)) # =====>sencond 2
print(next(obj)) # =====>third 3
- 使用 for 循环来验证
for item in obj:
print(item)
'''
=====>first
1
=====>sencond
2
=====>third
3
'''
------------------------------------------------------------
1、"iter_obj=obj.__iter__()" 拿到迭代器
2、触发 "iter_obj.__next__()" 拿到该方法的返回值,赋值给item
3、周而复始,直到函数内不在有 "yield", 即取值完毕
4、"for" 会检测到 "StopIteration" 异常,结束循环
五. yield 与 return 的区别
1.相同点
- 在返回值得角度, 用法都一样
2.不同点
- yield 可以返回多次值, 而 return 只能返回一次值
3.总结 yield
- 为我们提供了一种自定义迭代器的方式
- yield 可以暂停函数, 保存函数执行的状态, 然后使用 next 方法再次触发函数体代码的运行 (协程知识点)
4.应用示例
- 造一个无穷值
def my_range():
n = 0
while True:
yield n
n += 1
obj = my_range() # 一个生成器
print(obj) # <generator object my_range at 0x0000022784809F48>输出的是老母鸡内存地址
使用"next"取值
print(next(obj)) # 0
print(next(obj)) # 1
print(next(obj)) # 2
print(next(obj)) # 3
......等等..
使用 "for" 循环
for i in my_range(): # 也可以使用 for 循环取
print(i)
- 模仿内置函数 range( )
def my_range(start, stop, step = 1):
n = start
while n < stop:
yield n
n += step
使用 "next" 取值
obj = my_range(2 ,14, 2)
print(next(obj)) # 2
print(next(obj)) # 4
print(next(obj)) # 6
使用 "for" 循环
for line in my_range(2, 15, 3)
print(line)
六. yield 的应用
-
next
: 执行一次 -
send
: send 会传送一个值给 yield 关键字, 赋值给 yield 左边的的变量名, 再执行等同于 next 的功能继续执行下面的代码 -
close
: 当使用 close 时, 会关闭生成器, 无法在进行迭代取值, 取值则报 StopIteration 异常 -
喂狗示例: ps : "dog.send(None)" 的效果等于 "next(dog)"
def eat(name):
print('%s start eat' %name)
while True:
food = yield 1 # yield 接收 send 传过来的值赋值给 food
print('%s start eat %s'%(name,food))
dog = eat('派大星的狗') # 获得生成器
next(dog) # 派大星的狗 start eat
dog.send("海绵宝宝") # 派大星的狗 start eat 海绵宝宝 (send 自带 next 的执行功能)
dog.close() # 关闭这个生产器 (无法在进行取值)
next(dog) # 再次取值跑出异常 "StopIteration"