在 Python 中,yield
通常被认为是"生成多个值"的工具,但其实它的作用远不止如此。尤其当我们配合 .send()
方法使用时,yield
不只是"抛出值",还变成了一个表达式 ------ 能够接收来自外部的输入。
这篇文章将深入解释两个关键问题:
yield
表达式的值是从哪来的?- 使用
send()
和不使用send()
的区别是什么?
一、基本示例
python
def greeter():
name = yield "你是谁?"
yield f"你好,{name}"
g = greeter()
print(next(g)) # 输出: 你是谁?
print(g.send("张三")) # 输出: 你好,张三
重点一:send(x)
会把 x
赋值给上一个 yield
表达式
让我们重点关注这一行代码:
python
name = yield "你是谁?"
这是一个"暂停点 + 接收点":
-
yield "你是谁?"
会将"你是谁?"
发出(返回给调用者),并暂停函数; -
当我们调用
g.send("张三")
时,Python 会:- 恢复生成器的执行;
- 把
"张三"
作为yield
表达式的返回值; - 也就是:
name = "张三"
。
✅ 图示等价理解:
python
name = yield "你是谁?"
# 调用 g.send("张三") 后,相当于:
name = "张三"
重点二:如果不用 send()
,yield
表达式的值是 None
来看另一个例子:
python
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 表达式) |
三、思维模型类比:问答式通信
python
question = yield "你是谁?"
yield
提出一个问题;- 外部使用
send("张三")
作为回答; - 于是
question = "张三"
。
这就像是协程之间的双向通信,是构建调度器、LLM代理、LangGraph等系统的核心通信模式。
四、以三段式协程对话为例
python
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 协程通信的基础机制。