说我想拥有一个包含多个非托管资源的类,例如文件。我也喜欢该类的公共接口,允许用户以异常安全的方式使用它,即不泄漏非托管资源/让它们受垃圾收集器的支配,这不是垃圾收集器。 t保证在任何时候运行(确定性资源回收)。
例如,以下案例:
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
- 语句使用该类。)
我的问题是:实现我所希望的最简洁的方法是什么,最好是以我能够扩展到两个以上非托管资源的方式,以及并不会让我班级的公共界面变得太可怕(如果有的话)?我想到了一个与__init__
方法分开的初始化方法的想法,但听起来有点奇怪。
答案 0 :(得分:3)
如果您使用的是Python 3,这看起来像是contextlib.ExitStack
的工作。如果您使用的是Python 2,则可能会有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()