yield
的特点:懒惰、节省、分步
- 普通函数(return):一次性干完活,把结果全给你,函数结束。
yield
:干一点活,给你一点结果,歇会儿,等你再要时继续干。
特点:
- 懒惰执行:不一次性算完,只有你要时才算。
- 节省内存:不用把所有结果存起来,边生成边用。
- 分步返回:像流水线,一步步给你结果。
一个立刻能懂的例子
假设你要数1到5:
用 return
(普通方式)
def count_to_five():
result = [1, 2, 3, 4, 5] # 先把所有数准备好
return result
numbers = count_to_five()
for n in numbers:
print(n)
- 过程:
- 函数先把
[1, 2, 3, 4, 5]
全算出来。 - 返回整个列表。
- 你再循环打印。
- 函数先把
- 特点:一次性返回,内存里存了整个列表。
用 yield
(生成器方式)
def count_to_five():
for i in [1, 2, 3, 4, 5]:
yield i # 每次只给一个数
numbers = count_to_five()
for n in numbers:
print(n)
- 过程:
- 函数不一次性算完,而是返回一个“生成器”。
- 每次循环时,生成器只生成一个数(
yield i
),然后暂停。 - 你拿到一个数,打印,下次再要下一个。
- 输出:一样是
1 2 3 4 5
,但方式不同。 - 特点:
- 懒惰:每次只算一个数,不是全算好。
- 节省:内存里只存当前那个数,不存整个列表。
- 分步:像流水线,逐步给你。
你代码里的 yield
def _invoke(self, tool_parameters: dict[str, Any]):
yield self.create_json_message({"result": "Hello, world!"})
特点体现:
- 懒惰:不立刻生成所有结果,等你用
for
循环时才生成这个消息。 - 节省:只生成一个
ToolInvokeMessage
,不存多余东西。 - 分步:这里只有一步(一个
yield
),但如果加更多yield
,会逐步输出。
- 懒惰:不立刻生成所有结果,等你用
试试看:
tool = MyTestTool() messagestool = MyTestTool() messages = tool._invoke({"input": "test"}) # 返回生成器 for msg in messages: print(msg) # 只打印一次,因为只有一个 yieldTestTool() messagestool = MyTestTool() messages = tool._invoke({"inputtool = MyTestTool() messages = tool._invoke({"input": "test"}) # 返回生成器 for msg in messages: print(msg) # 只打印一次,因为只有一个 yieldyTestTool() messagestool = MyTestTool() messages = tool._invoke({"inputtool = MyTestTool() messages = tool._invoke({"input": "test"}) # 返回生成器 for msg in messages: print(msg) # 只打印一次,因为只有一个 yield
为什么你没觉得有特点?
- 因为只有一个
yield
:你代码里只yield
了一次,看起来跟return
差不多,所以感觉不出区别。 - 试试多个
yield
:def _invoke(self, tool_parameters: dict[str, Any]): yield self.create_json_message({"result": "Step 1"}) yield self.create_json_message({"result": "Step 2"})
- 跑一下:
for msg in tool._invoke({"input": "test"}): print(msg)
- 输出:
ToolInvokeMessage({"result": "Step 1"}) ToolInvokeMessage({"result": "Step 2"})
- 这时候特点就出来了:它分两步给你结果,而不是一次全给。
- 跑一下:
Java对比:为什么Java没这东西?
- Java的办法:用
List
或Iterator
,但得自己管理。public List<String> invoke() { return Arrays.asList("Hello, world!"); // 一次性返回 }
- 或者用
Iterator
:public Iterator<String> invoke() { Listpublic Iterator<String> invoke() { List<String> list = Arrays.asList("Step 1", "Step 2"); return list.iterator(); // 分步,但得先准备好列表 }
- 或者用
- Python的
yield
:不用自己写Iterator
,直接在函数里yield
,自动变成分步返回。
再举个生活例子
- 没
yield
:你去超市买5个苹果,收银员一次性给你5个,你拿回家。 - 有
yield
:收银员每次给你1个苹果,你拿一个吃一个,吃完再回去拿下一个。
验证你是否理解
试试这个:
def say_hello():
yield "Hi"
yield "there"
for word in say_hello():
print(word)
- 你觉得会输出什么?
- 答案:
Hi
和there
,分两行。 - 为什么:因为
yield
分两次给了你结果。
总结 yield
的特点
- 懒惰:不提前干完活,等你用时才干。
- 节省:不一次占用很多内存,边用边生成。
- 分步:像流水线,一块一块给你。
代码里因为只有一个 yield
,所以没发挥出这些特点。如果改成多个 yield
,你就会明显感觉到它跟 return
的不同。