【发布时间】:2021-01-28 19:29:03
【问题描述】:
我正在尝试 yield 在 with 语句中创建的上下文管理器。但是,发生了一些我不明白的事情:上下文管理器在产生之前关闭,即使生成器中的执行没有退出with 的范围。例如:
class CM:
def __enter__(self):
print('enter cm')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit cm')
def make_foo():
with CM() as cm:
print('before yield')
yield cm
print('after yield')
print('before make_foo')
foo = next(make_foo())
print('after make_foo')
输出
before make_foo
enter cm
before yield
exit cm
after make_foo
我在一个相关主题上看到了this thread,答案是关于对象被垃圾回收的时间——但是为什么cm 在返回给调用者使用之前会被垃圾回收?
编辑
改写时
foo_maker = make_foo()
foo = next(foo_maker)
那么CM没有关闭——所以看起来CM确实是GC,因为生成器是GC。但是它不应该被单独留下,因为它会被退回并可能在之后使用吗?
【问题讨论】:
-
contxt 管理器不是垃圾回收器,而是生成器对象,
.closees 它,导致with语句执行__exit__ -
并且
CM不是 gc'd。你为什么这么认为? -
您只调用了一次
next(),所以make_foo()在yield之后从未恢复。因此,with块永远没有机会退出。 -
这是一个有趣的问题。我要补充一点,cpython 中没有任何垃圾收集,有引用计数。他们不同。
标签: python generator contextmanager