【问题标题】:Is there a meaningful way to use context managers inside generators?有没有一种有意义的方式在生成器中使用上下文管理器?
【发布时间】:2011-06-01 15:00:48
【问题描述】:
from contextlib import contextmanager

@contextmanager
def context():
    print "entering"
    yield
    print "exiting"

def test():
    with context():
        for x in range(10):
            yield x

for x in test():
    if x == 5:
        break  # or raise

输出:

entering

有没有办法让python在for循环中断时自动调用context()的__exit__方法?或者其他实现相同目标的方法?我对生成器和上下文管理器的了解让我怀疑这是不可能的,但这使得上下文管理器在生成器内部相当无用,不是吗?在我看来,with 块内的 yield 语句应该引发危险信号,上下文管理器 __exit__ 可能无法运行

【问题讨论】:

    标签: python generator contextmanager


    【解决方案1】:

    好吧,你可以在 context() 函数中使用 try/finally 子句包装 yield:

    from contextlib import contextmanager
    
    @contextmanager
    def context():
        print "entering"
        try:
            yield
        finally:
            print "exiting"
    
    def test():
        with context():
            for x in range(10):
                yield x
    
    for x in test():
        if x == 5:
            break  # or raise
    

    输出:

    entering
    exiting
    

    编辑:如果您尝试:help(contextmanager),它将显示它是“典型”使用示例,其中他们使用 try/finally 子句包装 yield。

    【讨论】:

    • 这正是您应该做的:在循环 test() 被删除后,在 yield x 处引发 GeneratorExit()。这反过来又打破了with: for: 块。然后 contextmanager 再次捕获 GeneratorExit() 并在 context 的 yield 处提高它 - 这就是你必须捕获它的地方,否则 context 就在那里结束(毕竟它也是一个生成器,所以这个异常结束它默默地)不做清理。文档声明:“因此,您可以使用 try...except...finally 语句来捕获错误(如果有),或确保进行一些清理”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    • 2010-09-08
    • 2023-01-18
    • 2018-12-23
    • 2016-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多