在生成器中使用上下文管理器是否有意义的方法?

Lau*_*low 10 python generator contextmanager

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
Run Code Online (Sandbox Code Playgroud)

输出:

entering
Run Code Online (Sandbox Code Playgroud)

__exit__for-loop被中断时,有没有办法让python自动调用context()的方法?或者其他一些实现相同目标的方式?我对生成器和上下文管理器的了解让我怀疑它是不可能的,但是这使得上下文管理器在内部生成器中相当无用,不是吗?在我看来,块yield内的语句with应该引发一个红旗,上下文管理器__exit__可能无法运行.

Ger*_*rat 17

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

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
Run Code Online (Sandbox Code Playgroud)

输出:

entering
exiting
Run Code Online (Sandbox Code Playgroud)

编辑:如果您尝试:help(contextmanager),它将显示它的"典型"用法示例,其中使用try/finally子句包装yield.

  • 这正是你应该做的:在循环`test()`被删除之后,它会在`yield x`中引发`GeneratorExit()`.这反过来突破了`with:for:`块.然后contextmanager再次捕获`GeneratorExit()`并在`context`中以yield的形式引发它 - 这就是你必须捕获它的地方,否则`context`就在那里结束(毕竟它也是一个生成器,所以这个异常在没有进行清理的情况下静静地结束它.文档声明:"因此,您可以使用try ... except ... finally语句来捕获错误(如果有的话),或者确保进行一些清理" (2认同)