【问题标题】:Why is the context manager closed after it is yielded?为什么上下文管理器在产生后关闭?
【发布时间】:2021-01-28 19:29:03
【问题描述】:

我正在尝试 yieldwith 语句中创建的上下文管理器。但是,发生了一些我不明白的事情:上下文管理器在产生之前关闭,即使生成器中的执行没有退出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


【解决方案1】:

我认为这是因为您的方法定义和调用方式。

如果你不是 foo = next(make_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

【讨论】:

    猜你喜欢
    • 2018-04-15
    • 2015-10-01
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    相关资源
    最近更新 更多