在我的代码中,我需要能够正确打开和关闭设备,因此需要使用上下文管理器。虽然上下文管理器通常被定义为一个类__enter__
and __exit__
方法,似乎还可以装饰一个与上下文管理器一起使用的函数(请参阅最近的帖子 and 另一个很好的例子在这里).
在下面的(工作)代码片段中,我实现了两种可能性;只需要将注释行与另一行交换即可:
import time
import contextlib
def device():
return 42
@contextlib.contextmanager
def wrap():
print("open")
yield device
print("close")
return
class Wrap(object):
def __enter__(self):
print("open")
return device
def __exit__(self, type, value, traceback):
print("close")
#with wrap() as mydevice:
with Wrap() as mydevice:
while True:
time.sleep(1)
print mydevice()
我尝试的是运行代码并停止它CTRL-C
。当我使用Wrap
上下文管理器中的类__exit__
方法按预期调用(文本“关闭”打印在终端中),但是当我尝试使用相同的方法时wrap
函数时,文本“close”不会打印到终端。
我的问题:代码片段是否有问题,我是否遗漏了什么,或者为什么该行print("close")
没有用装饰函数调用?
文档中的示例为contextmanager
有点误导。之后的函数部分yield
并不真正对应__exit__
上下文管理器协议。文档中的关键点是:
如果块中发生未处理的异常,则会在生成器内发生yield 的位置重新引发异常。因此,您可以使用try...except...finally
语句来捕获错误(如果有),或确保进行一些清理。
因此,如果你想在 contextmanager 修饰的函数中处理异常,你需要编写自己的try
包裹着yield
并自己处理异常,在 a 中执行清理代码finally
(或者只是阻止异常except
并在之后执行清理try/except
)。例如:
@contextlib.contextmanager
def cm():
print "before"
exc = None
try:
yield
except Exception, exc:
print "Exception was caught"
print "after"
if exc is not None:
raise exc
>>> with cm():
... print "Hi!"
before
Hi!
after
>>> with cm():
... print "Hi!"
... 1/0
before
Hi!
Exception was caught
after
这一页还展示了一个有启发性的例子。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)