You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Generator类模拟yield from?最优实现方案探讨

问题:基于Generator类模拟yield from的最优实现方式

由于需要在生成器内部使用self引用,我采用Generator类而非生成器函数,但希望实现类似yield from的功能。示例生成器函数如下:

def gen1():
    yield "foo"

def gen2():
    t = gen1()
    yield from t
    yield "bla"

for i in gen2():
    print(i)

我编写了如下Generator类实现,请问这是模拟yield from的最优方式吗?

from collections.abc import Generator

class Test(Generator):
    def __init__(self):
        self.count = 5;
        
    def send(self, *args):
        print(f"Test.send({args})")
        self.count -= 1
        if self.count == 0:
            raise StopIteration()
        return "foo"

    def throw(self, value):
        print(f"Test.throw({value})")

class Test2(Generator):
    def __init__(self):
        self.count = 5;
        self.test = Test()

    def send(self, *args):
        if self.test:
            try:
                return self.test.send(*args)
            except StopIteration:
                self.test = None
        print(f"Test2.send({args})")
        self.count -= 1
        if self.count == 0:
            raise StopIteration()
        return "foo"

    def throw(self, value):
        print(f"Test2.throw({value})")

test2 = Test2()
while True:
    res = test2.send("bla")
    print(f"res = {res}")

注:关于继承(含多层继承)的问题已解决,仅需确认上述实现是否为最优方案。


回答

你的实现核心逻辑是正确的,但算不上最优,还有几个关键细节可以优化,让它更贴近原生yield from的行为:

  • 转发throw方法到子生成器:
    当前Test2的throw方法直接处理异常,没有转发给内部的test子生成器,而原生yield from会优先将异常转发给子生成器处理,只有子生成器抛出StopIteration时才会回到父生成器。修改后的throw方法如下:

    def throw(self, value):
        if self.test:
            try:
                return self.test.throw(value)
            except StopIteration:
                self.test = None
        print(f"Test2.throw({value})")
        raise value
    
  • 实现close方法:
    Generator抽象基类定义了close方法,用于清理生成器资源,原生yield from会调用子生成器的close方法,你的实现需要补充这部分逻辑:

    def close(self):
        if self.test:
            try:
                self.test.close()
            finally:
                self.test = None
        # 这里可以添加父生成器自身的清理逻辑
    
  • 处理子生成器的返回值:
    原生yield from会捕获子生成器抛出的StopIteration并提取其value属性作为返回值,当前实现没有处理这部分,如果你的场景需要用到子生成器的返回值,需要在捕获StopIteration时保存这个值:

    def send(self, *args):
        if self.test:
            try:
                return self.test.send(*args)
            except StopIteration as e:
                self.test = None
                self._subgen_return_value = e.value  # 保存子生成器返回值
        # 后续逻辑...
    
  • 代码复用与可读性:
    如果有多个类需要实现类似的yield from逻辑,可以抽取出通用的混合类或者工具函数,避免重复编写转发逻辑;另外用明确的状态变量(比如self._subgen_active)替代self.test = None,能提升代码的可读性。

补充这些细节后,你的实现就能更完整、健壮地模拟原生yield from的行为,同时保持代码的可维护性。


内容的提问来源于stack exchange,提问作者Goswin von Brederlow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 11:57:10