浅谈 Python 中的 yield——yield的返回值与send()的关系
在 Python 中,yield 通常被认为是“生成多个值”的工具,但其实它的作用远不止如此。尤其当我们配合 .send() 方法使用时,yield 不只是“抛出值”,还变成了一个表达式 —— 能够接收来自外部的输入。
这篇文章将深入解释两个关键问题:
yield表达式的值是从哪来的?- 使用
send()和不使用send()的区别是什么?
一、基本示例
def greeter():name = yield "你是谁?"yield f"你好,{name}"g = greeter()
print(next(g)) # 输出: 你是谁?
print(g.send("张三")) # 输出: 你好,张三
重点一:send(x) 会把 x 赋值给上一个 yield 表达式
让我们重点关注这一行代码:
name = yield "你是谁?"
这是一个“暂停点 + 接收点”:
-
yield "你是谁?"会将"你是谁?"发出(返回给调用者),并暂停函数; -
当我们调用
g.send("张三")时,Python 会:- 恢复生成器的执行;
- 把
"张三"作为yield表达式的返回值; - 也就是:
name = "张三"。
✅ 图示等价理解:
name = yield "你是谁?"
# 调用 g.send("张三") 后,相当于:
name = "张三"
重点二:如果不用 send(),yield 表达式的值是 None
来看另一个例子:
def greeter():name = yield "你是谁?"print(f"你好,{name}")g = greeter()
print(next(g)) # 第一次执行,返回 "你是谁?"
print(next(g)) # 第二次执行,没有 send,name 是多少?
✅ 输出:
你是谁?
你好,None
因为第二次使用的是 next(g),而不是 send(x),所以:
yield表达式的返回值默认是None。
二、完整对比总结表
| 操作方式 | 功能说明 | yield 表达式的值 |
|---|---|---|
next(generator) | 恢复执行但不提供返回值 | None |
generator.send(x) | 恢复执行并将 x 作为返回值 | x(赋值给 yield 表达式) |
三、思维模型类比:问答式通信
question = yield "你是谁?"
yield提出一个问题;- 外部使用
send("张三")作为回答; - 于是
question = "张三"。
这就像是协程之间的双向通信,是构建调度器、LLM代理、LangGraph等系统的核心通信模式。
四、以三段式协程对话为例
def dialogue():name = yield "你是谁?"age = yield f"你好,{name},你几岁?"yield f"{name},你今年 {age} 岁了!"g = dialogue()
print(next(g)) # → "你是谁?"
print(g.send("张三")) # → "你好,张三,你几岁?"
print(g.send(18)) # → "张三,你今年 18 岁了!"
输出:
你是谁?
你好,张三,你几岁?
张三,你今年 18 岁了!
五、总结
yield可以是表达式;send(x)把x作为上一个yield表达式的返回值;- 如果不用
send()而用next(),返回值默认是None; yield+send()构成了 Python 协程通信的基础机制。
🔚 推荐阅读
- Python官方文档:yield expressions
- PEP 342 – Coroutines via Enhanced Generators
