刚启动的Python生成器调用.close()方法的行为探究
Python生成器close()方法的行为与内存验证
已知测试示例
- 示例1:
执行以下代码:
def gen(): while True: yield 1 g = gen() g.send(1)
会抛出 TypeError: can't send non-None value to a just-started generator。
- 示例2:
执行以下代码:
def gen(): while True: try: yield 1 except GeneratorExit: print("exit") raise g = gen() next(g) g.close()
会打印 exit。
目标代码的行为与验证
代码实际行为
执行以下代码:
def gen(): while True: try: yield 1 except GeneratorExit: print("exit") raise g = gen() g.close()
实际表现为:
- 运行时无任何输出;
- 如果后续调用
next(g),会抛出StopIteration异常。
内存变化的验证方法
要验证close()操作后的内存释放情况,可以用以下几种方式:
- 用sys.getsizeof()查看对象自身内存
直接获取生成器对象在创建和close()后的内存占用,对比数值变化:
import sys def gen(): while True: try: yield 1 except GeneratorExit: print("exit") raise g = gen() print(f"生成器创建后内存占用: {sys.getsizeof(g)} 字节") g.close() print(f"调用close()后内存占用: {sys.getsizeof(g)} 字节")
注意:这个方法仅返回对象本身的内存大小,不包含其引用的内部状态,只能做基础参考。
- 用tracemalloc跟踪内存分配细节
tracemalloc可以精准记录内存的分配与释放,对比close()前后的内存快照:
import tracemalloc def gen(): while True: try: yield 1 except GeneratorExit: print("exit") raise tracemalloc.start() g = gen() snap_before = tracemalloc.take_snapshot() g.close() snap_after = tracemalloc.take_snapshot() # 输出内存变化前5项 stats = snap_after.compare_to(snap_before, 'lineno') print("内存变化统计:") for stat in stats[:5]: print(stat)
通过快照对比,能看到生成器内部状态相关内存的释放情况。
- 用gc模块查看引用与回收情况
生成器close()后内部状态被清理,引用计数下降,可通过gc模块观察:
import gc def gen(): while True: try: yield 1 except GeneratorExit: print("exit") raise g = gen() print(f"创建后生成器的引用列表: {gc.get_referrers(g)}") g.close() print(f"close后生成器的引用列表: {gc.get_referrers(g)}") # 手动触发垃圾回收 gc.collect()
引用列表的变化可以侧面反映生成器是否被标记为可回收。
背后的逻辑
生成器刚创建时还未执行到yield语句,处于未启动状态。此时调用close(),Python不会触发GeneratorExit异常的捕获逻辑(因为生成器还没进入yield的挂起状态),所以不会打印"exit"。同时,close()会直接将生成器标记为已关闭状态,后续调用next()自然会抛出StopIteration。
内存方面,close()会清理生成器的内部帧栈、局部变量等运行状态,大部分关联内存会被标记为可回收,等待Python垃圾回收器处理。
内容的提问来源于stack exchange,提问作者Labo
相关产品推荐
相关产品推荐

