python-如何重用自定义@ contextlib.contextmanager?

我试图创建一个包装,使上下文对象可选.当条件为真时,事物的行为应类似于包装的上下文对象,否则应表现为无操作上下文对象.本示例仅使用包装对象一次,但是失败了,它将被重用.

例:

import contextlib
from threading import Lock

@contextlib.contextmanager
def conditional_context(context, condition):
    if condition and context:
        with context:
            yield
    else:
        yield

use_locking = False
lock = conditional_context(Lock(), use_locking)
with lock:
    print('Foo')
with lock:
    print('Bar')

输出:

Foo
Traceback (most recent call last):
  File "example.py", line 16, in 
    with lock:
  File "/usr/lib/python3.5/contextlib.py", line 61, in __enter__
    raise RuntimeError("generator didn't yield") from None
RuntimeError: generator didn't yield

最佳答案

您不能使用contextlib.contextmanager做到这一点.正如在传递the docs时提到的那样,contextmanager创建的上下文管理器是一次性的.

如果您希望同一对象可以在多个with语句中重复使用,则必须使用__enter__和__exit__方法编写自己的类:

from threading import Lock


class ConditionalContext:

    def __init__(self, context, condition):
        self._context = context
        self._condition = condition

    def __enter__(self, *args, **kwargs):
        if self._condition:
            self._context.__enter__(*args, **kwargs)

    def __exit__(self, *args, **kwargs):
        if self._condition:
            self._context.__exit__(*args, **kwargs)


use_locking = False
lock = ConditionalContext(Lock(), use_locking)
with lock:
    print('Foo')
with lock:
    print('Bar')