python中的yield关键字

Python中yield关键字详解
部署运行你感兴趣的模型镜像

yield 是把一个普通函数变成 生成器函数 的关键字。它的核心作用是:产出一个值并“暂停”函数执行,保留当前局部状态;下次继续从暂停处往下执行。因此:
• return:一次性返回,函数结束。
• yield:返回一个值但不结束,下次迭代再继续(直到遇到 return 或运行到结尾)。

什么时候用 yield
1. 惰性计算、节省内存:一次产出一个值,而不是一次把所有结果装进列表。
2. 可中断/可恢复的流程:生成器在每次 yield 处暂停、恢复。
3. 数据管道:一段一段处理大文件/网络数据。
4. (进阶)协程风格:配合 .send() 向生成器“反向传值”。
5. (进阶)委托:用 yield from 把迭代转发给子生成器。

基础示例:把函数变成生成器

def squares(n):
    for i in range(n):
        yield i * i  # 每次产出一个值并暂停

g = squares(3)       # 只是创建生成器,不执行
next(g)              # -> 0
next(g)              # -> 1
next(g)              # -> 4

再 next 会 StopIteration(生成器耗尽)

实际使用更常见的是:

for x in squares(5):
    print(x)

流式处理/节省内存

def read_chunks(path, size=8192):
    with open(path, "rb") as f:
        while True:
            buf = f.read(size)
            if not buf:
                return         # 或者写 `break`,生成器结束
            yield buf         # 一块一块读,适合大文件

与 return 的关系
• 生成器里 return 会结束生成器;
• Python 3.3+ 允许 return value,这个 value 只能被 yield from 的调用方拿到(见下例)。

进阶一:send() 做“协程式”通信

你可以把值“发回去”给上一次 yield 表达式:

def averager():
    total = count = 0
    avg = None
    while True:
        x = yield avg      # 程序在这里暂停,等待外部 send(x)
        total += x
        count += 1
        avg = total / count

g = averager()
next(g)            # 先“预热”,让生成器跑到第一个 yield
print(g.send(10))  # -> 10.0
print(g.send(20))  # -> 15.0
print(g.send(30))  # -> 20.0

注意:未启动的生成器不能直接 send(非 None),必须先 next(g) 或 g.send(None)。

进阶二:yield from 委托给子生成器(PEP 380)
• 扁平化子迭代器的 yield;
• 透传 .send()/.throw()/.close();
• 接收子生成器的 return value。

def sub():
    yield 1
    yield 2
    return "done"   # 返回值供外层拿

def outer():
    result = yield from sub()  # 把迭代委托给 sub()
    print("sub returned:", result)

for _ in outer():
    pass

迭代过程中会产出 1、2;结束时打印:sub returned: done

异步生成器(了解即可)

在 async def 里用 yield 会得到 异步生成器,需要 async for 消费:

import asyncio

async def ticker(n):
    for i in range(n):
        yield i
        await asyncio.sleep(1)

async def main():
    async for x in ticker(3):
        print(x)

asyncio.run(main())

常见坑
• 只拿到生成器对象:忘了迭代它(for、next()、list())。
• 启动时 send:首次必须 next(g) 或 send(None)。
• 在 preload_app/多进程场景:把不可 fork 的资源(线程池/连接)放到启动钩子里,不要在定义生成器的模块顶层就执行。
• StopIteration 传播:不要在生成器内部显式 raise StopIteration(PEP 479 约束);用 return 结束。
• lambda 里不能用 yield。

小抄
• 想要“边算边用、少占内存” → 用 yield。
• 想把多个迭代器拼起来/代理 → 用 yield from。
• 想双向通信(把值送回生成器) → 用 .send();先预热。
• 需要把生成器结果一次性收集 → list(gen) 或 for 循环。

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值