Python 为什么上下文管理器在生成后关闭?
我试图Python 为什么上下文管理器在生成后关闭?,python,generator,contextmanager,Python,Generator,Contextmanager,我试图生成一个上下文管理器,它是在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
生成一个上下文管理器,它是在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
我在一个相关的主题上看到了,答案是关于对象被垃圾收集的时间——但是为什么cm
在返回供调用方使用之前会被垃圾收集
编辑
当你写作的时候
foo_maker = make_foo()
foo = next(foo_maker)
然后CM并没有关闭——所以看起来CM确实是GC,因为生成器是GC。但是,既然它被返回并可能在之后使用,那么它不应该被单独保留吗?我认为这是因为您的方法定义和您如何调用它
如果您不使用foo=next(make\u foo())
,请使用以下命令:
for i in make_foo():
print('thanks I saw cm')
结果是:
enter cm
before yield
thanks I saw cm
exit cm
after yield
after make_foo
contxt管理器不是垃圾收集的,生成器对象是垃圾收集的,这.close
将其删除,这将导致with
语句执行\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。你为什么这么认为?你只调用了next()
一次,所以make\u foo()
在产生后就再也没有恢复。因此,带
的块从未有机会退出。这是一个有趣的问题。我要补充的是,在cpython中没有任何垃圾收集,而是ref计数。他们的意见不同。