from functools import wraps from threading import RLock def lock_for_object(obj, locks={}): return locks.setdefault(id(obj), RLock()) def synchronized(call): assert call.__code__.co_varnames[0] in ['self', 'cls'] @wraps(call) def inner(*args, **kwds): with lock_for_object(args[0]): return call(*args, **kwds) return inner