上下文管理器作为装饰器,可以访问生成的对象
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())
(我实际使用的是一个带参数的包装器,但这只是一个包装器...)
我有一个对象的上下文管理器,可以像 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 explicitwith
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())
(我实际使用的是一个带参数的包装器,但这只是一个包装器...)