Я пытаюсь создать оболочку @synchronized, которая создает одну блокировку для каждого объекта и делает вызовы методов потокобезопасными. Я могу сделать это только в том случае, если я могу получить доступ к method.im_self метода в обернутом методе.
class B:
def f(self): pass
assert inspect.ismethod( B.f ) # OK
assert inspect.ismethod( B().f ) # OK
print B.f # <unbound method B.f>
print B().f # <bound method B.f of <__main__.B instance at 0x7fa2055e67e8>>
def synchronized(func):
# func is not bound or unbound!
print func # <function f at 0x7fa20561b9b0> !!!!
assert inspect.ismethod(func) # FAIL
# ... allocate one lock per C instance
return func
class C:
@synchronized
def f(self): pass
(1) Что сбивает с толку, так это то, что параметр func, переданный моему декоратору, меняет тип до того, как он будет передан в генератор-оболочку. Это кажется грубым и ненужным. Почему это происходит?
(2) Есть ли какая-то магия декоратора, с помощью которой я могу вызывать методы для объекта с мьютексом (т.е. одна блокировка для каждого объекта, а не для каждого класса).
ОБНОВЛЕНИЕ: существует множество примеров оберток @synchronized(lock). Однако на самом деле я хочу @synchronized(self). Я могу решить это следующим образом:
def synchronizedMethod(func):
def _synchronized(*args, **kw):
self = args[0]
lock = oneLockPerObject(self)
with lock: return func(*args, **kw)
return _synchronized
Однако, поскольку это намного эффективнее, я бы предпочел:
def synchronizedMethod(func):
lock = oneLockPerObject(func.im_self)
def _synchronized(*args, **kw):
with lock: return func(*args, **kw)
return _synchronized
Это возможно?