Python - 以错误安全的方式获取多个上下文管理器

问题描述 投票:0回答:1

下面的代码是否会安全地获取多个 FileLock 上下文管理器对象,并在出现任何错误时释放所有资源?

当使用多个上下文管理器资源时,资源获取必须是原子的(全部成功或全部失败)。如果出现任何错误,则需要释放所有已获取的资源。阅读

为类所拥有的对象编写上下文管理器的 Pythonic 方式

,但它看起来很复杂,并且希望有一个更简单的方法。如果有更好的方法,请推荐。 __enter__


python-3.x contextmanager
1个回答
0
投票
from contextlib import ( ExitStack ) from typing import ( Sequence, ContextManager, Optional, ) class MultiFileLocks: def __init__(self, filepaths: Sequence[str]): if filepaths is None or len(filepaths) == 0: raise ValueError(f"invalid filepath:[{filepaths}].") self._filepaths: Sequence[str] = [ str(pathlib.Path(_path).expanduser().resolve()) for _path in filepaths ] self._stack: Optional[ExitStack] = None self._locks: Optional[Sequence[FileLock]] = None def __enter__(self) -> ContextManager: with ExitStack() as temp_stack: _locks = [ temp_stack.enter_context(FileLock(_path)) for _path in self._filepaths ] self._stack = temp_stack.pop_all() self._locks = _locks return self def __exit__(self, exc_type, exc_value, traceback): self._stack.close() self._stack = None self._locks = None

来锁定,则最终可能会得到

哲学家就餐问题
的变体。 此类问题最简单的解决方案是对文件进行排序,例如按规范路径对它们进行排序,以便在单个部分排序中获取所有锁(此解决方案存在涉及公平性的缺陷,您可以在 Dining Philosophers 链接上阅读更多内容以获取更高级的解决方案)。

作为一个更小的问题,除非您需要在

MultiFileLock

返回后访问堆栈本身,否则您可以通过单独绑定

__enter__
方法来简化事情,
根据 
close
 上的示例,以避免明显存储堆栈本身(它仍然存储所有内容,从您的角度来看,这只是限制了复杂性)。
否则你看起来不错。

© www.soinside.com 2019 - 2024. All rights reserved.