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

刚启动的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()

实际表现为:

  1. 运行时无任何输出;
  2. 如果后续调用 next(g),会抛出 StopIteration 异常。

内存变化的验证方法

要验证close()操作后的内存释放情况,可以用以下几种方式:

  1. 用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)} 字节")

注意:这个方法仅返回对象本身的内存大小,不包含其引用的内部状态,只能做基础参考。

  1. 用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)

通过快照对比,能看到生成器内部状态相关内存的释放情况。

  1. 用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 04:52:35