Python中能否在生成器函数内部访问已yield的产出结果?
回答
Python 不存在你示例中提到的self.__yield__.__results__这类可直接获取yield产出统计、已产出结果的内置特性。
生成器的核心设计目标是惰性迭代、极低内存占用,默认不会缓存历史产出值,也不会内置统计产出次数的属性——如果默认做了这类缓存,遇到产出大量值的场景,生成器就会失去省内存的优势,和设计初衷相悖。
你可以根据自己的场景选下面几种合规的实现方式:
- 原生手动计数:这是性能最好、最符合Python惯例的写法,没有额外依赖和额外开销,只需要把计数累加逻辑放在
yield语句之后,确保只有真正成功产出值时才计数即可,就是你最开始写的实现:
import random def random_select(iterations): count = 0 for index in range(iterations): if random.randint(0, 9) > 4: yield index count += 1 assert count > 0
- 通用包装类统计:如果不想在每个生成器里重复写计数逻辑,可以实现一个轻量的生成器包装类,自动统计产出次数、按需缓存结果,对业务生成器代码无侵入:
from collections.abc import Generator import random class CountedGenerator(Generator): def __init__(self, source_gen): self._gen = source_gen self.yield_count = 0 self.results = [] def send(self, value): val = self._gen.send(value) self.yield_count += 1 self.results.append(val) return val def throw(self, typ, val=None, tb=None): return self._gen.throw(typ, val, tb) # 业务生成器不需要写计数逻辑 def random_select(iterations): for index in range(iterations): if random.randint(0, 9) > 4: yield index # 使用时包装即可 if __name__ == "__main__": gen = CountedGenerator(random_select(20)) for item in gen: # 正常处理迭代逻辑 print(item) assert gen.yield_count > 0
- 直接收集结果判断:如果你的场景本身就需要用到所有产出值,不需要依赖生成器的低内存特性,直接把生成器转成列表后判断长度即可,不需要单独维护计数:
results = list(random_select(10)) assert len(results) > 0 # 后续直接操作results列表即可
注意:不要尝试通过访问生成器的底层私有属性(比如gi_frame相关的内部变量)来 hack 计数,这类属性属于解释器内部实现细节,不同Python版本、不同解释器实现的行为完全不统一,没有任何兼容性保障,严禁在生产代码中使用。
内容的提问来源于stack exchange,提问作者TheRealVira
相关产品推荐
相关产品推荐

