如何从ExitStack

时间:2016-06-03 05:56:57

标签: python stack with-statement

我有一个名为Updater的长时间运行进程,它有提交给它的更新(到ETL系统)。更新具有通过向Updater的ExitStack添加上下文管理器来管理的资源需求。某些更新将包括新配置,这意味着必须从堆栈中释放受影响的资源,并添加新配置的资源版本。我需要这样的东西:

with ExitStack() as stack:
    ctx_manager = open("file.txt")
    f = stack.enter_context(ctx_manager)
    ...
    ctx_pop(ctx_manager, stack)  # remove the given context manager from the stack

以下是我已经开始工作的一个例子,但它依赖于访问受保护的成员。我希望可能会有一个不那么脏的'解决方案比:

def ctx_pop(cm, stack):
    for item in stack._exit_callbacks:
        if item.__self__ is cm:
            break
    else:
        raise KeyError(repr(cm))
    stack._exit_callbacks.remove(item)
    item(None, None, None)

编辑:添加已知解决方案

2 个答案:

答案 0 :(得分:1)

contextlib.ExitStack仅支持一次退出所有上下文管理器。您无法单独弹出上下文管理器。如果你想这样做,你应该使用ExitStack以外的东西来跟踪你的上下文管理器。

答案 1 :(得分:1)

您必须使用自己的ExitStack方法扩展pop

from contextlib import ExitStack
from collections import deque

class ExitStackWithPop(ExitStack):
    def pop(self, cm):
        callbacks = self._exit_callbacks
        self._exit_callbacks = deque()
        found = None
        while callbacks:
            cb = callbacks.popleft()
            if cb.__self__ == cm:
                found = cb
            else:
                self._exit_callbacks.append(cb)
        if not found:
            raise KeyError("context manager not found")
        found(None, None, None)