【问题标题】:Context manager as a decorator with access to the yielded object上下文管理器作为装饰器,可以访问产生的对象
【发布时间】:2020-06-08 12:46:20
【问题描述】:

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

with MyContextManager as cm:
    cm.do_something()

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

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

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

【问题讨论】:

    标签: python python-decorators contextmanager


    【解决方案1】:

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

    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()) 
    

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

    【讨论】:

      【解决方案2】:

      没有。 documentation 中明确提到了这一点。

      请注意,将上下文管理器用作函数装饰器时还有一个限制:无法访问 __enter__() 的返回值。如果需要该值,则仍然需要使用显式的with 语句。

      【讨论】:

        猜你喜欢
        • 2023-03-25
        • 2010-12-24
        • 1970-01-01
        • 2019-05-09
        • 2015-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多