请看下面的示例:
from contextlib import AbstractContextManager, contextmanager
class MyClass(AbstractContextManager):
_values = {}
@contextmanager
def using(self, name, value):
print(f'Allocating {name} = {value}')
self._values[name] = value
try:
yield
finally:
print(f'Releasing {name}')
del self._values[name]
def __enter__(self):
return self.using('FOO', 42).__enter__()
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with MyClass():
print('Doing work...')我希望上面的代码能打印以下内容:
Allocating FOO = 42
Doing work...
Releasing FOO相反,这是正在印刷的:
Allocating FOO = 42
Releasing FOO
Doing work...为什么FOO被急切地释放了?
发布于 2022-11-11 01:02:45
您在这里创建两个上下文管理器。实际上,只有其中一个上下文管理器实现正确。
您的using上下文管理器很好,但是您也在MyClass上实现了上下文管理器协议,并且MyClass上的实现已经中断。using创建一个using上下文管理器,输入它,返回上下文管理器的__enter__返回的内容,然后将上下文管理器抛出。
退出using上下文管理器时不退出MyClass()上下文管理器。你根本就没退出过!将using上下文管理器扔掉。它被回收,当它被回收时,生成器会被自动调用close,作为正常的生成器清理的一部分。这会向生成器抛出一个GeneratorExit异常,从而触发finally块。
Python并不保证何时会进行这种清理(或者实际上,如果会发生这种情况),但是在实践中,当using上下文管理器无法到达时,CPython的引用计数机制就会触发清理。
除此之外,如果_values应该是一个实例变量,则应该将其设置为__init__方法中的self._values = {}。现在,它是一个类变量。
https://stackoverflow.com/questions/74396909
复制相似问题