【问题标题】:Getting a context manager created with @contextmanager to work properly with exceptions让使用 @contextmanager 创建的上下文管理器在异常情况下正常工作
【发布时间】:2019-01-03 20:47:42
【问题描述】:

我有以下代码

from contextlib import contextmanager

@contextmanager
def simple_context_manager():
    print("starting context manager")
    yield
    print("finished context manager")

try:
    with simple_context_manager():
        raise RuntimeError
except RuntimeError:
    print("Caught the error")
print("Moving on")

现在打印出来了

starting context manager
Caught the error
Moving on

这告诉我上下文管理器没有关闭。 如何让它关闭并打印“完成的上下文管理器”行?

由于我使用的是装饰器,我没有专用的__exit__ 函数,我认为应该根据this 调用。

所以我不确定如何让我的上下文管理器在其上下文中发生错误的情况下退出。

【问题讨论】:

    标签: python python-3.x error-handling contextmanager


    【解决方案1】:

    你需要一个 try-finally:

    @contextmanager
    def simple_context_manager():
        print("starting context manager")
        try:
            yield
        finally:
            print("finished context manager")
    

    如果异常从with 语句传播出来,@contextmanager 装饰器会将throw 异常传递到yield 处的装饰生成器中。 finally 让我们不管是否发生异常都执行一个清理块,所以我们使用它。

    【讨论】:

    • 问题是:为什么默认没有实现这种行为?我的意思是,with 语句是 Python 中最接近 C++ RAII 的东西,唯一真正重要使用它的情况就是透明的异常处理。当我们不需要在引发异常时调用上下文管理器的退出函数时可能会出现什么情况?
    • @Semisonic:@contextmanager 装饰器的设计者必须选择不同的方式将异常信息传递到生成器(并将异常抑制信息传递到生成器之外)才能正常工作。他们选择的设计可能是在这里传达异常信息最自然的方式,我不知道他们是否意识到有多少人会忘记他们需要finally
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    相关资源
    最近更新 更多