Python中的yield

半兽人 发表于: 2025-04-09   最后更新时间: 2025-04-09 18:59:19  
{{totalSubscript}} 订阅, 81 游览

yield 的特点:懒惰、节省、分步

  • 普通函数(return):一次性干完活,把结果全给你,函数结束。
  • yield:干一点活,给你一点结果,歇会儿,等你再要时继续干。

特点

  1. 懒惰执行:不一次性算完,只有你要时才算。
  2. 节省内存:不用把所有结果存起来,边生成边用。
  3. 分步返回:像流水线,一步步给你结果。

一个立刻能懂的例子

假设你要数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. 函数先把 [1, 2, 3, 4, 5] 全算出来。
    2. 返回整个列表。
    3. 你再循环打印。
  • 特点:一次性返回,内存里存了整个列表。

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)
  • 过程
    1. 函数不一次性算完,而是返回一个“生成器”。
    2. 每次循环时,生成器只生成一个数(yield i),然后暂停。
    3. 你拿到一个数,打印,下次再要下一个。
  • 输出:一样是 1 2 3 4 5,但方式不同。
  • 特点
    • 懒惰:每次只算一个数,不是全算好。
    • 节省:内存里只存当前那个数,不存整个列表。
    • 分步:像流水线,逐步给你。

你代码里的 yield

def _invoke(self, tool_parameters: dict[str, Any]):
    yield self.create_json_message({"result": "Hello, world!"})
  • 特点体现

    1. 懒惰:不立刻生成所有结果,等你用 for 循环时才生成这个消息。
    2. 节省:只生成一个 ToolInvokeMessage,不存多余东西。
    3. 分步:这里只有一步(一个 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的办法:用 ListIterator,但得自己管理。
    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)
  • 你觉得会输出什么?
  • 答案:Hithere,分两行。
  • 为什么:因为 yield 分两次给了你结果。

总结 yield 的特点

  1. 懒惰:不提前干完活,等你用时才干。
  2. 节省:不一次占用很多内存,边用边生成。
  3. 分步:像流水线,一块一块给你。

代码里因为只有一个 yield,所以没发挥出这些特点。如果改成多个 yield,你就会明显感觉到它跟 return 的不同。

更新于 2025-04-09
在线,11小时前登录

查看python更多相关的文章或提一个关于python的问题,也可以与我们一起分享文章