news 2026/5/1 4:42:29

Python:yield 表达式详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python:yield 表达式详解

在 Python 中,yield 并不是一种“特殊的返回语句”,也不是为惰性计算或循环结构单独设计的语法技巧。从执行模型的角度看,yield 的核心作用在于:将一次函数执行拆解为一个可暂停、可恢复、可逐步推进的执行过程,并以表达式的形式暴露这一执行边界。

理解 yield,并不是理解“生成器怎么用”,而是理解 Python 如何将执行状态对象化,并使其能够参与函数调用、迭代与控制流程之中。

一、从函数调用语义说起:普通函数是一段一次性执行过程

先从普通函数的执行语义入手:

def f(): a = 1 b = 2 return a + b

当执行:

result = f()

解释器的行为可以概括为:

1、根据 def 语句创建函数对象(该函数对象内部关联了一个代码对象)

2、调用函数时,创建一个新的帧对象,即“执行帧”

3、从函数体起始位置开始顺序执行指令

4、遇到 return 语句:

• 计算返回值

• 销毁执行帧

• 将结果返回给调用方

普通函数的执行帧是一次性的。一旦 return 被执行,该次执行过程即告结束,其执行状态不会被保留,也不可能被恢复。

因此,普通函数在语义上描述的是:从开始到结束的一次完整执行帧生命周期。

二、yield 表达式语法与执行语义定位

1、yield 是表达式,而不是语句

在 Python 3 中,yield 是一种表达式(expression),而不是语句(statement)。

yield 表达式的基本语法结构:

yield <expression>

说明:

(1)<expression> 是一个普通的 Python 表达式;该表达式在执行过程中被求值,其结果作为本次迭代中产出的值交还给调用方。

(2)yield <expression> 的语义作用在于:在执行过程中产出一个值,并暂停当前执行帧。

当 <expression> 被省略时:

yield

其语义等价于:

yield None

即产出值为 None,但暂停执行的语义保持不变。

2、yield 对函数调用语义的根本影响

一旦函数体中出现 yield 表达式,解释器在语法分析阶段就会将该函数判定为生成器函数。这一判定结果会直接影响该函数在调用阶段的语义:

• 调用普通函数 → 立即创建执行帧并执行函数体

• 调用生成器函数 → 返回一个生成器对象,而不立即执行函数体

也就是说,yield 改变的并不是函数体中的某一步行为,而是从定义层面改变了函数调用的执行模型与返回结果类型。

从语言设计角度看,yield 的引入并非为了简化循环或节省内存,而是为了允许:函数的执行过程本身成为一个可被拆解、可被对象化、可被外部逐步驱动的运行期实体。

3、普通函数与生成器函数:定义层与执行层的差异

从定义层面看,Python 中的函数可以分为两类:

• 普通函数:函数体中不包含 yield

• 生成器函数:函数体中至少包含一条 yield 表达式

这一差异在 def 语句执行时即已确定,并体现在函数对象所关联的代码对象上。

两类函数在调用语义上的根本区别在于:

• 调用普通函数时,解释器立即创建执行帧并执行代码

• 调用生成器函数时,解释器返回一个生成器对象,而暂不创建执行帧

生成器对象可以被理解为对生成器函数一次潜在执行过程的封装。

它本身并不等同于执行帧,而是一个运行期控制对象,用于在需要时创建、保存并恢复执行帧。

三、yield 的核心语义:冻结当前执行帧

对于包含 yield 的函数而言,def 语句仅创建函数对象,调用该函数时才返回生成器对象。

执行帧的创建与激活,则发生在生成器对象被首次推进时(如 next() 或 send(None))。

示例:

def g(): x = 1 yield x x += 1 yield x + 1

当执行:

gen = g()next(gen)

解释器的执行过程为:

1、调用 g(),返回生成器对象

2、调用 next(gen):

→ 创建并激活执行帧

→ 从函数体起始位置开始执行

3、执行至 yield x:

→ 对表达式 x 求值

→ 将该值交还给调用方

→ 冻结当前执行帧的状态(包括指令位置、局部变量绑定及相关执行上下文)

这里所谓的“冻结”,指的是执行帧的暂停。即,函数的执行过程尚未完成,其执行状态被完整保留下来,等待后续恢复。

四、恢复执行与执行终止:yield 与 return 的语义分野

当生成器对象被多次推进时,解释器不会重新调用生成器函数,也不会重新创建执行帧。

gen = g()print(next(gen)) # 1print(next(gen)) # 3print(next(gen)) # StopIteration

执行过程是:

1、第一次 next(gen):

→ 创建并激活执行帧

→ 执行至第一个 yield,返回 yield 表达式的值

→ 然后冻结执行帧

2、第二次 next(gen):

→ 恢复此前冻结的执行帧,从上一次 yield 之后继续执行

→ 执行至第二个 yield,返回此 yield 表达式的值

3、第三次 next(gen):

→ 恢复冻结的执行帧,从第二次 yield 之后继续执行

→ 已到生成器函数底部,无法继续推进,抛出 StopIteration,销毁执行帧

整个过程中,推进的始终是同一个执行帧。

由此可以清晰地区分 yield 与 return 的本质差异:

(1)yield 表示执行过程的暂停点

• 执行帧被保留

• 执行状态可恢复

(2)return 表示执行过程的终止点

• 执行帧被销毁

• 执行过程不可恢复

当生成器函数运行至末尾,或在生成器函数内显式执行 return 时:

• 解释器向调用方抛出 StopIteration

• 执行帧被销毁

• 生成器对象进入终止态

因此,两者的区别并不在于是否“返回值”,而在于是否保留并允许继续推进当前执行帧。

五、yield 作为表达式:值的双向流动与 send 机制

绝大多数 Python 表达式的值,均在其执行当下立即确定。但 yield 是一个例外。

yield 表达式的产出值在执行当下确定,而该表达式的求值结果则延迟到下一次恢复执行时,由外部注入。

示例:

def gen(): x = yield 1 yield x

当执行:

g = gen()next(g) # 产出 1g.send("hello") # 将 "hello" 注入

g.send("hello") 并不是向生成器“整体”发送一个值,而是将 "hello" 作为上一次暂停点处的 yield 1 这个表达式的求值结果,然后将该值绑定给变量 x。

可以这样说,第一次 next(g) 大致等价于:

g.send(None)

也就是说,首次可使用 send() 向生成器对象发送 None 值来创建并激活执行帧。

不过,要注意的是,在生成器尚未启动之前,不能直接使用 send() 向生成器发送非 None 值,解释器将抛出 TypeError。原因是:

• 尚未创建执行帧

• 尚不存在暂停点

因而不存在可接收值的 yield 表达式。

六、yield from 的基本语义概览

yield from 是一种用于委托执行控制权的表达式。它在一段时间内暂停当前生成器的执行,并将执行推进、值注入、异常处理与终止请求统一转交给被委托对象;在被委托对象完成后,再恢复自身执行并接收其完成态返回值。

请参阅:

《Python:yield from 表达式详解》

📘 小结

yield 是一种用于冻结执行帧的表达式。它并不返回生成器对象,而是在生成器执行过程中产出值并暂停当前执行帧,从而将一次函数执行拆解为多个可恢复的执行阶段。作为表达式,yield 还支持在恢复执行时接收外部注入的值。

理解 yield 的语义,有助于从执行模型层面把握生成器、send 与 yield from 等机制的统一设计思想。

“点赞有美意,赞赏是鼓励”

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:58:27

一键实现:Lychee-rerank-mm让图片与文本匹配变得超简单

一键实现&#xff1a;Lychee-rerank-mm让图片与文本匹配变得超简单 去发现同类优质AI镜像&#xff1a;https://ai.csdn.net/ 你是否遇到过这些场景&#xff1a; 翻遍几十张产品图&#xff0c;却找不到最贴合文案描述的那张主图&#xff1b;给设计师发了“黄昏海边穿亚麻长裙…

作者头像 李华
网站建设 2026/4/18 10:03:38

WuliArt Qwen-Image Turbo实际作品:AI生成中国二十四节气主题插画系列

WuliArt Qwen-Image Turbo实际作品&#xff1a;AI生成中国二十四节气主题插画系列 1. 为什么是二十四节气&#xff1f;——当传统美学遇上轻量AI绘图引擎 你有没有试过&#xff0c;用一句话让AI画出“清明时节雨纷纷”的画面&#xff1f;不是简单堆砌关键词&#xff0c;而是真…

作者头像 李华
网站建设 2026/4/15 19:58:07

3步搞定中文NLP!RexUniNLU零样本模型部署全攻略

3步搞定中文NLP&#xff01;RexUniNLU零样本模型部署全攻略 你是不是也遇到过这些场景&#xff1a; 客服系统要从用户留言里自动提取人名、公司名和问题类型&#xff0c;但没标注数据&#xff0c;没法训练模型&#xff1b;市场团队想快速对上千条产品评论做情感分类&#xff…

作者头像 李华
网站建设 2026/4/29 15:24:02

Qwen3-ASR模型蒸馏技术:小模型大性能

Qwen3-ASR模型蒸馏技术&#xff1a;小模型大性能 最近开源界有个挺火的事儿&#xff0c;就是阿里千问团队把他们的语音识别模型Qwen3-ASR给开源了。这事儿为什么值得关注呢&#xff1f;因为这次开源的模型里&#xff0c;有个只有0.6B参数的小家伙&#xff0c;性能却相当能打。…

作者头像 李华
网站建设 2026/4/28 6:13:24

LaTeX科研写作革命:Magma智能体自动生成学术论文图表

LaTeX科研写作革命&#xff1a;Magma智能体自动生成学术论文图表 科研工作者最头疼的事情是什么&#xff1f;不是实验失败&#xff0c;不是数据分析&#xff0c;而是那些看似简单却极其耗时的图表格式调整和LaTeX排版工作。 作为一名长期与LaTeX打交道的科研人员&#xff0c;我…

作者头像 李华