假设我希望有一个包含多个非托管资源的类,比如文件。我还希望该类的公共接口允许用户以异常安全的方式使用它,即不泄漏非托管资源/将它们置于垃圾收集器的摆布之下,垃圾收集器永远不能保证在任何时候运行(确定性资源回收)。
以下面的案例为例:
class Gizmo(object):
def __init__(self, filepath1, filepath2):
self._file1 = open(filepath1, 'rb')
self._file2 = open(filepath2, 'rb')
def __enter__(self):
return self
def __exit__(self):
self.close()
return False
def __del__(self):
self.close()
def frob(self):
...manipulate the files...
def close(self):
self._file1.close()
self._file2.close()这不是异常安全的,因为如果在__init__中打开第二个文件的行失败,第一个文件就会泄漏,因为它将任由垃圾收集器摆布(无论我是否通过with-statement使用类)。
我的问题是:实现我想要的东西的最干净的方法是什么,最好是能够扩展到两个以上的非托管资源的方式,并且不会对我的类的公共接口造成太严重的混乱(如果有的话)?我想到了将初始化方法与__init__方法分开的想法,但这听起来有点奇怪。
发布于 2016-01-27 04:06:31
如果你使用的是Python3,这看起来像是contextlib.ExitStack的工作。如果您使用的是Python2,似乎可以使用此功能的backport。
from contextlib import ExitStack
class Gizmo(object):
def __init__(self, filepath1, filepath2):
with ExitStack() as stack:
# If opening the second file fails,
# unwinding the stack will close the first file.
self._file1 = stack.enter_context(open(filepath1, 'rb'))
self._file2 = stack.enter_context(open(filepath2, 'rb'))
# It worked! But we don't want to close the files when the with statement ends.
# Take the files off the stack without closing them
# (and put them on a new stack).
self._exitstack = stack.pop_all()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_tb):
return self._exitstack.__exit__(exc_type, exc_value, exc_tb)
def __del__(self):
self.close()
def frob(self):
...manipulate the files...
def close(self):
# __del__ will try to close a Gizmo even if we couldn't set up its _exitstack,
# so don't try to close a nonexistent _exitstack.
if hasattr(self, '_exitstack'):
# The stack calls __exit__ on all the files, exactly as if we were
# exiting a "with open(...) as file1, open(...) as file2" block.
# If closing one file fails, we'll still try to close the other.
self._exitstack.close()https://stackoverflow.com/questions/35022619
复制相似问题