Possible to create a @synchronized decorator that's aware of a method's object?

Go read:

  • https://github.com/GrahamDumpleton/wrapt/tree/develop/blog

and in particular:

  • https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/07-the-missing-synchronized-decorator.md
  • https://github.com/GrahamDumpleton/wrapt/blob/develop/blog/08-the-synchronized-decorator-as-context-manager.md

The wrapt module then contains the @synchronized decorator described there.

  • https://pypi.python.org/pypi/wrapt

The full implementation is flexible enough to do:

@synchronized # lock bound to function1
def function1():
    pass 

@synchronized # lock bound to function2
def function2():
    pass 

@synchronized # lock bound to Class
class Class(object):  

    @synchronized # lock bound to instance of Class
    def function_im(self):
        pass 

    @synchronized # lock bound to Class
    @classmethod
    def function_cm(cls):
        pass

    @synchronized # lock bound to function_sm
    @staticmethod
    def function_sm():
        pass

Along with context manager like usage as well:

class Object(object):  

    @synchronized
    def function_im_1(self):
        pass  

    def function_im_2(self):
        with synchronized(self):
            pass

Further information and examples can also be found in:

  • http://wrapt.readthedocs.org/en/latest/examples.html

There is also a conference talk you can watch on how this is implemented at:

  • https://www.youtube.com/watch?v=EB6AH-85zfY&t=1s

(1) What's confusing is that the func parameter passed to my decorator changes type before it gets passed into the wrapper-generator. This seem is rude and unnecessary. Why does this happen?

It doesn't! Rather, function objects (and other descriptors) produce their __get__'s results when that method of theirs is called -- and that result is the method object!

But what lives in the class's __dict__ is always the descriptor -- specifically, the function object! Check it out...:

>>> class X(object):
...   def x(self): pass
... 
>>> X.__dict__['x']
<function x at 0x10fe04e60>
>>> type(X.__dict__['x'])
<type 'function'>

See? No method objects around anywhere at all!-)

Therefore, no im_self around either, at decoration time -- and you'll need to go with your introspection-based alternative idea.


You can't get self at decoration time because the decorator is applied at function definition time. No self exists yet; in fact, the class doesn't exist yet.

If you're willing to store your lock on the instance (which is arguably where a per-instance value should go) then this might do ya:

def synchronizedMethod(func):
    def _synchronized(self, *args, **kw):
         if not hasattr(self, "_lock"): self._lock = oneLockPerObject(self)
         with self._lock: return func(self, *args, **kw)
    return _synchronized

You could also generate the lock in your __init__() method on a base class of some sort, and store it on the instance in the same way. That simplifies your decorator because you don't have to check for the existence of the self._lock attribute.