Python中的普通上下文管理器

时间:2018-02-21 14:14:57

标签: python python-2.7 with-statement

我的资源可以是R1类型,需要锁定或R2类型 这不需要它:

class MyClass(object):   # broken
    def __init__ (self, ...):
        if ...:
            self.resource = R1(...)
            self.lock = threading.Lock()
        else:
            self.resource = R2(...)
            self.lock = None

    def foo(self):   # there are many locking methods
        with self.lock:
            operate(self.resource)

如果self.lockNone,则上述情况显然会失败。

我的选择是:

  1. if

    def foo(self):
        if self.lock:
            with self.lock:
                operate(self.resource)
        else:
            operate(self.resource)
    
    • 缺点:太冗长
    • pro:不会创建不必要的threading.Lock
  2. 始终将self.lock设置为threading.Lock

    • pro:代码简化
    • 缺点:with self.lock似乎相对昂贵 (与磁盘i / o相当!)
  3. 定义一个简单的锁类:

    class TrivialLock(object):
        def __enter__(self): pass
        def __exit__(self, _a, _b, _c): pass
        def acquire(self): pass
        def release(self): pass
    

    并使用None代替R2

    • pro:简单代码
    • 缺点:我必须定义TrivialLock
  4. 问题

    1. 社区首选哪种方法?
    2. 无论(1),有没有人真正定义类似的东西 TrivialLock? (我实际上预计会有类似的东西 在标准库中......)
    3. 我的观察结果是锁定成本与a相当 write是否符合预期?

1 个答案:

答案 0 :(得分:1)

我会定义TrivialLock。但是,它可能更加微不足道,因为您只需要一个上下文管理器,而不是锁定。

class TrivialLock(object):
    def __enter__(self):
        pass
    def __exit__(*args):
        pass

使用contextlib

,您可以更加轻松
import contextlib

@contextlib.contextmanager
def TrivialLock():
    yield

self.lock = TrivialLock()

由于yield可以是表达式,因此您可以定义内联TrivalLock

self.lock = contextlib.contextmanager(lambda: (yield))()

请注意括号; lambda: yield无效。但是,生成器表达式(yield)使它成为一次性上下文管理器;如果您尝试在第二个with语句中使用相同的值,则会出现Runtime错误,因为generator已用尽。