5

这是我正在使用的代码:

from contextlib import contextmanager
from functools import wraps
class with_report_status(object):

    def __init__(self, message):
        self.message = message

    def __call__(self, f):
        @wraps(f)
        def wrapper(_self, *a, **kw):
            try:
                return f(_self, *a, **kw)
            except:
                log.exception("Handling exception in reporting operation")
                if not (hasattr(_self, 'report_status') and _self.report_status):
                    _self.report_status = self.message
                raise

        return wrapper

class MyClass(object):

    @contextmanager
    @with_report_status('unable to create export workspace')
    def make_workspace(self):
        temp_dir = tempfile.mkdtemp()
        log.debug("Creating working directory in %s", temp_dir)
        self.workspace = temp_dir
        yield self.workspace
        log.debug("Cleaning up working directory in %s", temp_dir)
        shutil.rmtree(temp_dir)

    @with_report_status('working on step 1')
    def step_one(self):
        # do something that isn't a context manager

问题是,@with_report_status不会像预期的那样屈服@contextmanager。但是,我也不能反过来包装它,因为@contextmanager返回一个生成器对象(我认为!)而不是值本身。

我怎样才能让@contextmanager装饰者玩得开心?

4

2 回答 2

3

尝试将 @contextmanager 移动到装饰器列表的底部。

于 2017-03-13T19:31:41.253 回答
0

这是一个奇怪的问题:@contextmanager返回一个上下文管理器,而不是一个生成器。但是出于某种原因,您希望将该上下文管理器视为一个函数?这不是你可以做的事情,他们没有共同点。

我认为您想要的是一个MyClass.make_workspace上下文管理器,并且report_status在异常情况下也有一个字段。为此,您需要自己编写一个上下文管理器,在它的__exit__方法中设置这个字段,在@contextmanager这里帮不了你。

您可以进行子类contextlib.GeneratorContextManager化以避免大部分工作。它没有记录,所以使用来源,卢克。

于 2011-01-19T05:16:44.900 回答