如何在父生成器停止时让嵌套生成器完成后续逻辑?
问题分析
原代码运行时,top()在counter>2时break退出迭代,此时子生成器child_1和child_2的生成器对象会因失去引用被Python垃圾回收,直接终止执行,不会运行yield语句后的print逻辑。
核心结论
如果完全不修改child_1、child_2的嵌套生成器结构,仅修改top(),无法实现让子生成器完成后续逻辑的需求。因为生成器中yield之后的代码只有在正常迭代至结束,或通过try-finally捕获生成器关闭事件时才会执行。
可行解决方案(允许修改生成器或top()逻辑)
方案1:用try-finally捕获生成器关闭事件
在子生成器的yield循环外包裹try-finally块,确保生成器被关闭时执行后续逻辑:
def top(): counter = 0 gen = child_1() for ch in gen: print(ch) counter += 1 if counter > 2: break # 显式关闭生成器,触发finally块 gen.close() def child_1(): try: for ch in child_2(): yield ch finally: print("child_1 logic has finished") def child_2(): try: for ch in "123456789": yield ch finally: print("child_2 logic has finished") if __name__ == '__main__': top()
运行输出:
1 2 3 child_2 logic has finished child_1 logic has finished
方案2:break后继续迭代生成器(忽略后续值)
在top()的break之后,继续迭代生成器至结束,触发子生成器的后续逻辑:
def top(): counter = 0 gen = child_1() for ch in gen: print(ch) counter += 1 if counter > 2: break # 迭代剩余生成器内容,不处理返回值 for _ in gen: pass def child_1(): for ch in child_2(): yield ch print("child_1 logic has finished") def child_2(): for ch in "123456789": yield ch print("child_2 logic has finished") if __name__ == '__main__': top()
运行输出与方案1一致。
方案3:用上下文管理器封装清理逻辑
通过上下文管理器自动处理生成器的后续迭代,简化top()的代码:
from contextlib import contextmanager @contextmanager def ensure_generator_cleanup(gen): try: yield gen finally: # 自动迭代完生成器剩余内容 for _ in gen: pass def top(): counter = 0 with ensure_generator_cleanup(child_1()) as gen: for ch in gen: print(ch) counter += 1 if counter > 2: break def child_1(): for ch in child_2(): yield ch print("child_1 logic has finished") def child_2(): for ch in "123456789": yield ch print("child_2 logic has finished") if __name__ == '__main__': top()
内容的提问来源于stack exchange,提问作者Paz
相关产品推荐
相关产品推荐

