gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 01:51:43 24 4
gpt4 key购买 nike

在我的代码中,我需要能够正确打开和关闭设备,因此需要使用上下文管理器。虽然上下文管理器通常被定义为具有 __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__ 方法按预期被调用(文本“关闭”打印在终端中),但是当我尝试与 wrap 功能相同,文本“关闭”不会打印到终端。

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

最佳答案

contextmanager 文档中的示例有些误导。 yield 之后的函数部分并不真正对应于上下文管理器协议(protocol)的__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 之后执行清理)。例如:

@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 函数不像 python 中的 contextmanager 类那样工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15447130/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com