生成器

生成器#

生成器是一种特殊的迭代器,可以允许用户自定义迭代逻辑。与迭代器相比,生成器的主要区别在于:

  • 迭代器是系统内置的,不能被重写。
  • 生成器是用户自定义的,可以重写迭代逻辑。

生成器可以通过两种方式创建:

  1. 生成器表达式:这是一种类似于列表推导式的表达式,只不过它的结果是一个生成器,而不是列表。
  2. 生成器函数:这是一种特殊的函数,它使用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

生成器可以通过多种方式调用:

  1. 使用next函数来获取下一个值:

    print(next(gen))  # 输出:0
    print(next(gen))  # 输出:1
    
  2. 使用for循环和next函数来获取多个值:

    for i in range(3):
        print(next(gen))  # 输出:2, 3, 4
    
  3. 使用for循环来获取所有的值:

    for i in gen:
        print(i)  # 输出:5, 6, 7, 8, 9
    
  4. 使用list函数来一次性获取所有的值:

    gen = (i for i in range(10))
    print(list(gen))  # 输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

注意,当生成器的所有值都被获取后,再次调用next函数会引发StopIteration异常。

生成器函数#

生成器函数是创建生成器的另一种方式。它使用yield关键字来产生值。yieldreturn类似,但有以下区别:

  • yieldreturn都会把值返回出去。
  • 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
posted @   江寒雨  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示
主题色彩