python3上下文管理器强制提前退出

时间:2016-12-13 15:23:32

标签: python-3.x contextmanager

我需要创建一个上下文管理器,当满足某些条件时,可以强制它提前退出。

更多详情:

上下文管理器需要处理检查/锁定/释放资源。在__enter__上,上下文管理器需要检查资源是否已锁定。如果是,我希望在不执行上下文中的代码的情况下调用__exit__。否则,上下文管理器获取资源,执行上下文代码,并清除__exit__中的资源。

它可能看起来像这样:

class my_context_manager:
    def __enter__(self):
        if resource_locked():
            self.__exit__(None, ResourceLockedException(), None)
        else:
            acquire_resource()

    def __exit__(self, *exc_info):
        if not isinstance(exc_info[1], ResourceLockedException):
            release_resource()
        else:
            log.warn("Resource already in use.")

上面的代码实际上并不起作用,因为在__exit__内调用__enter__并不会阻止上下文中的代码被执行。

或者,我可以从ResourceLockedException中抛出__enter__,但后来__exit__不会被调用,因为异常将从上下文管理器本身抛出。我希望能够捕获异常,记录警告,如果资源被锁定则不输入上下文。

这归结为找到一些早期关闭上下文的方法,以便调用__exit__并且不执行上下文代码。有没有办法调整上述任何一个想法来做到这一点?或者还有另一种方式吗?

1 个答案:

答案 0 :(得分:1)

是的,您无法像这样手动拨打__exit__。另一种选择只是raise异常,让另一个构造管理它。您可以使用try-except或掀起另一个上下文管理器来记录这些:

from contextlib import contextmanager

@contextmanager
def log_exception():
    try:
        yield
    except ResourceLockedException as e:
        log.warn(e)

并将原始上下文管理器更改为:

class my_context_manager:
    def __enter__(self):
        if True:
            raise ResourceLockedException("Resource already in use")
        acquire_resource()
    def __exit__(self):
        release_resource()

并将其命名为:

with log_exception(), my_context_manager():
    # do things when resource acquired. 

当然,您可以在其中使用try-except并嵌套with,或者使用if子句。