首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的contextmanager-function不像python中的contextmanager类那样工作?

为什么我的contextmanager-function不像python中的contextmanager类那样工作?
EN

Stack Overflow用户
提问于 2013-03-16 16:19:16
回答 1查看 2.3K关注 0票数 9

在我的代码中,我需要能够正确地打开和关闭设备,因此需要使用上下文管理器。虽然上下文管理器通常被定义为具有__enter____exit__方法的类,但似乎也可以修饰一个函数以与上下文管理器一起使用(请参阅a recent postanother nice example here)。

在下面的(工作的)代码片段中,我实现了两种可能性;一种只需要将注释行与另一种交换:

代码语言:javascript
复制
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")行?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-16 16:30:54

contextmanager文档中的示例有些误导。yield之后的函数部分并不真正对应于上下文管理器协议的__exit__。文档中的关键点是:

如果块中发生未处理的异常,则在生成器内的产生器发生点重新引发该异常。因此,您可以使用try...except...finally语句来捕获错误(如果有的话),或者确保进行一些清理。

因此,如果您想要处理上下文管理器修饰的函数中的异常,您需要编写自己的try来包装yield并自己处理异常,在finally中执行清理代码(或者在except中阻止异常并在try/except之后执行清理)。例如:

代码语言:javascript
复制
@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还展示了一个具有启发性的示例。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15447130

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档