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

Lat*_*der 6 contextmanager python-3.x

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

更多细节:

上下文管理器需要处理检查/锁定/释放资源.在__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.")
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jim*_*ard 4

是的,你不能__exit__像这样手动调用。另一种选择就是简单地raise处理异常并让另一个构造来管理它。您可以使用try-except或启动另一个上下文管理器来记录这些:

from contextlib import contextmanager

@contextmanager
def log_exception():
    try:
        yield
    except ResourceLockedException as e:
        log.warn(e)
Run Code Online (Sandbox Code Playgroud)

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

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

并用以下方式调用它:

with log_exception(), my_context_manager():
    # do things when resource acquired. 
Run Code Online (Sandbox Code Playgroud)

当然,您可以简单地使用 atry-except并嵌套with在其中,或者使用一个if子句。