Reputation: 60014
My resource can by of type R1
which requires locking or of type R2
which does not require it:
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)
The above obviously fails if self.lock
is None
.
if
:
def foo(self):
if self.lock:
with self.lock:
operate(self.resource)
else:
operate(self.resource)
threading.Lock
always set self.lock
to threading.Lock
with self.lock
appears to be relatively expensive
(comparable to disk i/o!)define a trivial lock class:
class TrivialLock(object):
def __enter__(self): pass
def __exit__(self, _a, _b, _c): pass
def acquire(self): pass
def release(self): pass
and use it instead of None
for R2
.
TrivialLock
TrivialLock
? (I actually expected that something like that would be
in the standard library...)write
conforms to expectations?Upvotes: 3
Views: 746
Reputation: 531055
I would define TrivialLock
. It can be even more trivial, though, since you just need a context manager, not a lock.
class TrivialLock(object):
def __enter__(self):
pass
def __exit__(*args):
pass
You can make this even more trivial using contextlib
:
import contextlib
@contextlib.contextmanager
def TrivialLock():
yield
self.lock = TrivialLock()
And since yield
can be an expression, you can define TrivalLock
inline instead:
self.lock = contextlib.contextmanager(lambda: (yield))()
Note the parentheses; lambda: yield
is invalid. However, the generator expression (yield)
makes this a single-use context manager; if you try to use the same value in a second with
statement, you get a Runtime
error because the generator
is exhausted.
Upvotes: 3