Nei*_*l G 7 python contextmanager
在这个问题中,我定义了一个包含上下文管理器的上下文管理器.完成此嵌套最简单的正确方法是什么?我最后打电话来self.temporary_file.__enter__()
了self.__enter__()
.但是,self.__exit__
我很确定我必须调用self.temporary_file.__exit__(type_, value, traceback)
finally块,以防引发异常.如果出现问题,我应该设置type_,value和traceback参数self.__exit__
吗?我检查过contextlib
,但找不到任何实用程序来帮助解决这个问题.
来自问题的原始代码:
import itertools as it
import tempfile
class WriteOnChangeFile:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.temporary_file = tempfile.TemporaryFile('r+')
self.f = self.temporary_file.__enter__()
return self.f
def __exit__(self, type_, value, traceback):
try:
try:
with open(self.filename, 'r') as real_f:
self.f.seek(0)
overwrite = any(
l != real_l
for l, real_l in it.zip_longest(self.f, real_f))
except IOError:
overwrite = True
if overwrite:
with open(self.filename, 'w') as real_f:
self.f.seek(0)
for l in self.f:
real_f.write(l)
finally:
self.temporary_file.__exit__(type_, value, traceback)
Run Code Online (Sandbox Code Playgroud)
Pet*_*rin 10
创建上下文管理器的简单方法是contextlib.contextmanager
.像这样的东西:
@contextlib.contextmanager
def write_on_change_file(filename):
with tempfile.TemporaryFile('r+') as temporary_file:
yield temporary_file
try:
... some saving logic that you had in __exit__ ...
Run Code Online (Sandbox Code Playgroud)
然后用with write_on_change_file(...) as f:
.声明
的正文with
将被执行"而不是" yield
.如果你想捕捉身体中发生的任何异常,请将yield
自身包裹在一个try
块中.
临时文件将始终正确关闭(当其with
块结束时).
contextlib.contextmanager
对于函数来说效果很好,但是当我需要一个类作为上下文管理器时,我使用以下实用程序:
class ContextManager(metaclass=abc.ABCMeta):
"""Class which can be used as `contextmanager`."""
def __init__(self):
self.__cm = None
@abc.abstractmethod
@contextlib.contextmanager
def contextmanager(self):
raise NotImplementedError('Abstract method')
def __enter__(self):
self.__cm = self.contextmanager()
return self.__cm.__enter__()
def __exit__(self, exc_type, exc_value, traceback):
return self.__cm.__exit__(exc_type, exc_value, traceback)
Run Code Online (Sandbox Code Playgroud)
这允许使用来自 的生成器语法声明 contextmanager 类@contextlib.contextmanager
。它使得嵌套 contextmanager 变得更加自然,而无需手动调用__enter__
和__exit__
。例子:
class MyClass(ContextManager):
def __init__(self, filename):
self._filename = filename
@contextlib.contextmanager
def contextmanager(self):
with tempfile.TemporaryFile() as temp_file:
yield temp_file
... # Post-processing you previously had in __exit__
with MyClass('filename') as x:
print(x)
Run Code Online (Sandbox Code Playgroud)
我希望这是在标准库中......