生成器
生成器#
生成器是一种特殊的迭代器,可以允许用户自定义迭代逻辑。与迭代器相比,生成器的主要区别在于:
- 迭代器是系统内置的,不能被重写。
- 生成器是用户自定义的,可以重写迭代逻辑。
生成器可以通过两种方式创建:
- 生成器表达式:这是一种类似于列表推导式的表达式,只不过它的结果是一个生成器,而不是列表。
- 生成器函数:这是一种特殊的函数,它使用
yield
关键字来产生值。
生成器表达式#
gen = (i for i in range(10))
print(gen) # 输出:<generator object <genexpr> at 0x7f1d1f7df200>
# 判断类型
from collections import Iterator, Iterable
print(isinstance(gen, Iterator)) # 输出:True
生成器可以通过多种方式调用:
-
使用
next
函数来获取下一个值:print(next(gen)) # 输出:0 print(next(gen)) # 输出:1
-
使用
for
循环和next
函数来获取多个值:for i in range(3): print(next(gen)) # 输出:2, 3, 4
-
使用
for
循环来获取所有的值:for i in gen: print(i) # 输出:5, 6, 7, 8, 9
-
使用
list
函数来一次性获取所有的值:gen = (i for i in range(10)) print(list(gen)) # 输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
注意,当生成器的所有值都被获取后,再次调用next
函数会引发StopIteration
异常。
生成器函数#
生成器函数是创建生成器的另一种方式。它使用yield
关键字来产生值。yield
与return
类似,但有以下区别:
yield
和return
都会把值返回出去。yield
每次返回时,会记住上次离开时执行的位置,下次再调用生成器时,会从上次执行的位置往下走。return
则会直接终止函数,每次都从头开始调用。
yield()#
### 生成器函数
def mygen():
print("111")
yield 1
print("222")
yield 2
print("333")
yield 3
生成器可以通过next
函数来获取下一个值:
gen = mygen() # 初始化生成器函数,返回生成器对象
print(next(gen)) # 输出:1
print(next(gen)) # 输出:2
print(next(gen)) # 输出:3
注意,当生成器的所有值都被获取后,再次调用next
函数会引发StopIteration
异常。
生成器函数可以被优化,例如在处理大数据时,可以使用生成器来逐步获取数据:
def mygen():
for i in range(1, 101):
yield i
gen = mygen()
for i in range(30):
print(next(gen))
send()#
生成器函数还可以使用send
方法来发送值给yield
:
def mygen():
print("start")
res = yield "内部1"
print(res, "<==内部==>")
res = yield "内部2"
print(res, "<==内部==>")
res = yield "内部3"
print(res, "<==内部==>")
print("end")
gen = mygen()
gen.send(None) # 第一次调用生成器时,必须发送None
gen.send("100")
gen.send("200")
"""
print("111") yield 1 保存当前第3行代码的状态,把1返回,并且等待下一次调用
# 第二次调用
从上一次保存的位置13行往下走, print("222") yield 2 保存当前第5行代码的状态,把2返回,并且等待下一次调用
# 第三次调用
从上一次保存的位置16行往下走, print("333") yield 3 保存当前第7行代码的状态,把3返回,并且等待下一次调用
# 第四次调用
因为没有更多的yield 返回数据,所有停止迭代.出现报错异常.
"""
#生成式的优化场景
def mygen():
for i in range(1,101):
yield i
# 初始化生成器函数 => 生成器
gen = mygen()
print("<=====>")
for i in range(30):
num = next(gen)
print("我的球衣号码是{}".format(num))
print("<=====>")
for i in range(40):
num = next(gen)
print("我的球衣号码是{}".format(num))
# next和send区别:
next 只能取值
send 不但能取值,还能发送值
# send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接受不到send的发送值
注意,第一次调用生成器时,因为还没有遇到yield
保存的代码位置,所以无法发送数据,必须发送None。最后一个yield
无法接收到send
的值。
#
yield from#
生成器函数还可以使用yield from
关键字来返回一个可迭代对象的所有值:
def mygen():
lst = ["张磊","李亚峰","刘一峰","王同培"]
yield from lst
gen = mygen()
print(next(gen)) # 输出:"张磊"
print(next(gen)) # 输出:"李亚峰"
print(next(gen)) # 输出:"刘一峰"
print(next(gen)) # 输出:"王同培"
生成器函数可以用来实现复杂的算法,例如斐波那契数列:
def mygen(maxval):
a, b = 0, 1
i = 0
while i < maxval:
yield b
a, b = b, a + b
i += 1
gen = mygen(10)
for i in range(3):
print(next(gen)) # 输出:1, 1, 2
for i in range(5):
print(next(gen)) # 输出:3, 5, 8, 13, 21
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~