生成器详解
Posted zx125
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成器详解相关的知识,希望对你有一定的参考价值。
生成器(generator)
什么是生成器
生成器是一种特殊的迭代器,生成器实现了迭代器协议__iter__(),__next__()
生成器解决什么问题
如果有一亿的数据要我们处理,我们通过列表的方式来访问的话,这一亿的数据是存放在内存的,这样会非常的消耗内存的,但是如果我们使用生成器的话,每当处理一个数据的时候,内存中只是相当于存了一个数据,这样可以节省大量的内存
简单案例
当生成器对象__next__()
的时候,生成器函数会执行到下一个yield,并会返回一个参数
例一
def zx():
yield 1
print(1)
if __name__ == '__main__':
zx=zx()
data=zx.__next__()
print(data)
1
例二
触发StopIteration异常的两种方式
1.迭代完最后一个元素后,触发StopIteration异常
def zx():
yield 1
print(1)
if __name__ == '__main__':
zx=zx()
data=zx.__next__()
data=zx.__next__()
1
Traceback (most recent call last):
File "C:/Users/Administrator/Desktop/01python/研究/生成器/t1.py", line 8, in <module>
data=zx.__next__()
StopIteration
2.运行生成器函数的时候遇到return,return的值,会成为异常的说明值,如例子的2
def zx():
yield 1
return 2
print(1)
yield 3
if __name__ == '__main__':
zx=zx()
data=zx.__next__()
data=zx.__next__()
Traceback (most recent call last):
File "C:/Users/Administrator/Desktop/01python/研究/生成器/t1.py", line 10, in <module>
data=zx.__next__()
StopIteration: 2
迭代器对象和生成器的产生区别
迭代器对象是通过可迭代对象的__iter__()
生成的
zx=[1,2,3,4,5,6,7,8,9]
z1=zx.__iter__()
生成器的创建方式类似生成对象的方式
def zx():
for i in range(10):
yield i
z1=zx()
send方法
协程的实现主要就是靠的生成器的send方法
例子1-错误使用
def dog():
print('小乌')
while True:
food = yield
if food == '骨头':
yield '好吃'
else:
yield '旺旺旺'
xw = dog() #只是用于返回一个生成器对象,函数并不会执行下去
print(xw.send('骨头'))
出现错误,不能给刚创建的生成器发送非空的值
Traceback (most recent call last):
File "C:/Users/Administrator/Desktop/01python/研究/生成器/t5_send.py", line 10, in <module>
print(xw.send('骨头'))
TypeError: can't send non-None value to a just-started generator
报错信息说不能发送非空的值,那我们来试试发送一个None会发生什么
print(xw.send(None))
执行成功了
小乌
None
其实也可以用__next__()
也能做到这个打印结果
print(xw.__next__())
结果一样
小乌
None
结论
1.__next__()
的效果其实和send(None)一样
2.yield默认返回None
例子2-正确使用
def dog():
print('小乌')
while True:
food = yield
if food == '骨头':
yield '好吃'
else:
yield '旺旺旺'
xw = dog() #只是用于返回一个生成器对象,函数并不会执行下去
print(xw.__next__())
print(xw.send('骨头'))
结果
小乌
None
好吃
结论
1.当生成器刚创建完成,第一次使用先next或者send(None),不能直接send(非空参数)
2.send()有给yield的赋值功能
总结
1.__next__()
的效果其实和send(None)一样
2.当生成器刚创建完成,第一次使用先next或者send(None),不能直接send(非空参数)
3.send()方法就相当于__next__()
和赋值功能的结合
生成器实现计数器和协程
计数器
def jishu():
i = 0
while True:
zx = yield i
if zx == "按一下":
i+=1
elif zx == "重置":
i=0
js=jishu()
print(js.__next__())
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("按一下"))
print(js.send("重置"))
print(js.send("按一下"))
print(js.send("按一下"))
0 初始化
1 按一下
2
3
4
0 重置
1
2
协程
吃包子
def consumer(name):
print(f"name老板上包子")
while True:
baozi = yield
print(f"name:吃了baozi")
def producer():
for i in range(2):
print('厨师做了两个包子')
c1.send(f"肉包i")
c2.send(f"菜包i")
c1 = consumer("小黄")
c2 = consumer("小乌")
c1.__next__()
c2.__next__()
producer()
小黄老板上包子
小乌老板上包子
厨师做了两个包子
小黄:吃了肉包0
小乌:吃了菜包0
厨师做了两个包子
小黄:吃了肉包1
小乌:吃了菜包1
以上是关于生成器详解的主要内容,如果未能解决你的问题,请参考以下文章
MybatisPlus的代码生成器 使用详解(整合springboot)
MybatisPlus的代码生成器 使用详解(整合springboot)