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 に答える