在我的代码中,我需要能够正确地打开和关闭设备,因此需要使用上下文管理器。虽然上下文管理器通常被定义为具有__enter__和__exit__方法的类,但似乎也可以修饰一个函数以与上下文管理器一起使用(请参阅a recent post和another nice example here)。
在下面的(工作的)代码片段中,我实现了两种可能性;一种只需要将注释行与另一种交换:
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__方法如预期的那样被调用(文本'close‘在终端中打印),但是当我用wrap函数尝试同样的事情时,文本'close’没有打印到终端。
我的问题是:代码片段是否有问题,我是否遗漏了什么,或者为什么没有使用修饰函数调用print("close")行?
发布于 2013-03-16 16:30:54
contextmanager文档中的示例有些误导。yield之后的函数部分并不真正对应于上下文管理器协议的__exit__。文档中的关键点是:
如果块中发生未处理的异常,则在生成器内的产生器发生点重新引发该异常。因此,您可以使用
try...except...finally语句来捕获错误(如果有的话),或者确保进行一些清理。
因此,如果您想要处理上下文管理器修饰的函数中的异常,您需要编写自己的try来包装yield并自己处理异常,在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
afterThis page还展示了一个具有启发性的示例。
https://stackoverflow.com/questions/15447130
复制相似问题