在我的代码中,我需要能够正确打开和关闭设备,因此需要使用上下文管理器。尽管通常使用__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__
方法被称为expeced(终端上打印了文本“close”),但是当我使用wrap
函数尝试相同的操作时,文本“close”却没有打印到终端。我的问题:代码段是否存在问题,我是否丢失了某些内容,或者为什么装饰函数未调用
print("close")
行? 最佳答案
contextmanager
文档中的示例有些误导。 yield
之后的函数部分实际上并不与上下文管理器协议(protocol)的__exit__
对应。文档中的关键点是:
因此,如果要在contextmanager装饰的函数中处理异常,则需要编写自己的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
after
This page还显示了一个说明性示例。
关于python - 为什么我的contextmanager-function不能像python中的contextmanager类那样工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15447130/