【问题标题】:How can I mix decorators with the @contextmanager decorator?如何将装饰器与 @contextmanager 装饰器混合使用?
【发布时间】:2011-01-19 04:42:40
【问题描述】:

这是我正在使用的代码:

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 与装饰器配合得很好?

【问题讨论】:

    标签: python decorator contextmanager


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

      您可以继承contextlib.GeneratorContextManager 以避免大部分工作。它没有记录,所以请使用源,Luke。

      【讨论】:

      • 实际上,open() 的工作方式相同,用作上下文管理器或用作类。所以这是有道理的,而且是可能的。
      猜你喜欢
      • 1970-01-01
      • 2014-06-17
      • 2021-01-06
      • 2015-02-01
      • 2016-03-07
      • 2013-02-06
      • 1970-01-01
      • 2022-08-15
      • 2021-07-19
      相关资源
      最近更新 更多