HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

A non-blocking lock decorator in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
nonblockingpythondecoratorlock

Problem

I needed to impose on a Python method the following locking semantics: the method can only be run by one thread at a time. If thread B tries to run the method while it is already being run by thread A, then thread B immediately receives a return value of None.

I wrote the following decorator to apply these semantics:

from threading import Lock

def non_blocking_lock(fn):
    fn.lock = Lock()

    @wraps(fn)
    def locker(*args, **kwargs):
        if fn.lock.acquire(False):
            try:
                return fn(*args, **kwargs)
            finally:
                fn.lock.release()

    return locker


This works in my testing so far. Does anyone notice any gotchas or have any suggestions for improvements?

Revised version

After the suggestions by @RemcoGerlich, I have added a docstring and kept the lock local to the decorator:

from threading import Lock

def non_blocking_lock(fn):
    """Decorator. Prevents the function from being called multiple times simultaneously.

    If thread A is executing the function and thread B attempts to call the
    function, thread B will immediately receive a return value of None instead.

    """
    lock = Lock()

    @wraps(fn)
    def locker(*args, **kwargs):
        if lock.acquire(False):
            try:
                return fn(*args, **kwargs)
            finally:
                lock.release()

    return locker

Solution

I think this will work fine and it's very close to how I would write it myself.

A few small things come to mind:

-
There's no documentation of any kind that explains what the semantics are, and they're not explicit either (the return None if the lock isn't acquired is entirely implicit). I would put the short explanation you put in this question into a docstring, and/or add an explicit else: return None to the if statement.

-
is there any reason why the lock object is exposed to the outside world by making it a property of the function (fn.lock) ? I would simply make it a local variable, so that it's hidden. But I'm not sure.

Context

StackExchange Code Review Q#42802, answer score: 6

Revisions (0)

No revisions yet.