我有一个从上下文管理器生成的函数:
def producer(pathname):
with open(pathname) as f:
while True:
chunk = f.read(4)
if not chunk:
break
yield chunk当生成器完全被消耗时,这并不是一个问题,因为在上一次迭代期间,生成器在收益率语句之后恢复执行,循环中断,我们很好地退出上下文管理器。
然而,如果发电机只被部分消耗,并且没有更多的消费者完全使用它,那么生成器会永远暂停吗?在这种情况下,我们永远不会退出上下文管理器。这是否意味着文件将在其余的程序执行过程中保持打开状态?或者至少在发电机被收集垃圾之前?这是我应该自己处理的一个角落情况,还是我可以依靠Python运行时来及时关闭悬空的上下文管理器?
FWIW,我见过Generator and context manager at the same time和How to use a python context manager inside a generator,但我不认为他们真的回答了同样的问题。除非我漏掉了什么?
发布于 2019-12-04 04:32:00
如果无法使用整个生成器,则在垃圾收集生成器之前不会清除上下文管理器,如果涉及引用周期,或者在非CPython解释器上运行,这可能需要相当长的时间。
您可以通过生成器迭代器close-ing来解决这个问题;所有生成器函数都在生成的生成器迭代器上提供a close method,生成迭代器在其中引发GeneratorExit;with语句中的异常气泡等等,以确保正确地清除它们。
要使其发生在保证的时间点上,您可以通过use contextlib.closing获得生成器本身的保证关闭:
from contextlib import closing
with closing(producer(mypath)) as produced_items:
for item in produced_items:
# Do stuff, maybe break loop early即使您break、return或引发异常,with控制produced_items也会对其进行close,这反过来将调用对其中的with语句的清理。
https://stackoverflow.com/questions/58974675
复制相似问题