为什么我的contextmanager函数不能像python中的contextmanager类那样工作?

2024-04-27 16:04:11 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的代码中,我需要能够正确地打开和关闭设备,从而了解使用上下文管理器的必要性。虽然上下文管理器通常被定义为具有__enter____exit__方法的类,但是似乎也有可能修饰一个用于上下文管理器的函数(请参见a recent postanother 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__方法被称为expeed(文本'close'在终端中打印),但是当我用wrap函数尝试相同的操作时,文本'close'不会打印到终端。在

我的问题是:代码片段有问题吗,我是否遗漏了什么,或者为什么没有用修饰函数调用print("close")行?在


Tags: 方法函数代码import管理器closereturndevice
1条回答
网友
1楼 · 发布于 2024-04-27 16:04:11

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

If an unhandled exception occurs in the block, it is reraised inside the generator at the point where the yield occurred. Thus, you can use a try...except...finally statement to trap the error (if any), or ensure that some cleanup takes place.

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

^{1}$

This page还显示了一个有指导意义的示例。在

相关问题 更多 >