上下文管理器作为装饰器,可以访问生成的对象

Context manager as a decorator with access to the yielded object

我有一个对象的上下文管理器,可以像 open 上下文管理器一样使用,例如

with MyContextManager as cm:
    cm.do_something()

我知道如果使用 contextlib.ContextDecorator 创建一个简单的上下文管理器,它可以变成一个装饰器。如果使用装饰器,是否也可以访问上下文管理器产生的对象?例如。给定上面的上下文管理器,类似于:

@cmdecorator
def my_function(self, cm):
    cm.do_something

我无法让它工作。要么我遗漏了一些微不足道的东西(希望如此),要么这是不可能的......它最终只是语法糖,但如果可能的话我很感兴趣。

没有。 documentation.

中明确提到了这一点

Note that there is one additional limitation when using context managers as function decorators: there’s no way to access the return value of __enter__(). If that value is needed, then it is still necessary to use an explicit with statement.

回答我自己的问题:虽然没有自动机制,但很容易编写一个装饰器来做到这一点(使用硬编码关键字参数):

def patch_cm(f):
    @functools.wraps(f)
    def decorated(*args, **kwds):
        with MyContextManager() as cm:
            kwds['cm'] = cm
            return f(*args, **kwds)

    return decorated

可以使用(这里是单元测试):

class MyContextManagerTest(TestCase):
    @patch_cm
    def test_context_decorator(self, cm):
        cm.do_something()
        self.assertTrue(cm.done()) 

与以下内容相同:

def test_context_decorator(self):
    with MyContextManager() as cm:
       cm.do_something()
       self.assertTrue(cm.done()) 

(我实际使用的是一个带参数的包装器,但这只是一个包装器...)