Ð
Богун Дмитрий
Hello.
I try make some weird thing. I want to get from code like this:
class master:
...
class slave:
...
m = master()
s = m.slave()
s.master is m
Last expression must be true. I want link "master" to be set
automatically by master object while creating slave object. Additional
requirement - "master" link must be available for constructor of slave
object.
Best what I can get is:
import functools
from weakref import WeakKeyDictionary
from threading import RLock
class meth_wrap(object):
def __init__(self, func):
object.__init__(self)
self.func = func
functools.update_wrapper(self, func, updated=())
class lazy_attr(meth_wrap):
def __get__(self, obj, type=None):
if obj is None:
return self
val = self.func(obj)
setattr(obj, self.__name__, val)
return val
class slave_mixin(object):
@lazy_attr
def master(self):
m = slave_gen._unbound_master
assert m is not None, '"Slave" object can\'t find master link.
Is it was correctly created? obj:%s' % repr(self)
return m
class slave_gen(meth_wrap):
_storage = WeakKeyDictionary()
# ИÑпользуетÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð¾
_unbound_master = None
_lock = RLock()
def __get__(self, mobj, type=None):
if mobj is None:
return self.func
d = {
'm': mobj,
'w': self}
obj = self.delay_init()
self._storage[obj] = d
functools.update_wrapper(obj, self.func, updated=())
return obj
class delay_init(object):
def __call__(self, *args, **kw_args):
d = slave_gen._storage[self]
slave_gen._lock.acquire()
try:
slave_gen._unbound_master = d['m']
obj = d['w'].func(*args, **kw_args)
obj.master = d['m']
slave_gen._unbound_master = None
finally:
slave_gen._lock.release()
return obj
def __getattr__(self, attr):
d = slave_gen._storage[self]
return getattr(d['m'], attr)
def __setattr__(self, attr, val):
d = slave_gen._storage[self]
return setattr(d['m'], attr, val)
class Master(object):
@slave_gen
class Slave(slave_mixin):
def __init__(self):
slave_mixin.__init__(self)
print 'Slave.__init__: self.master: ', self.master
if __name__ == '__main__':
m = Master()
s = m.Slave()
print 's.master: ', s.master
It works, by looking little weird... and I can't find way to escape from
using lock at object creation phase. It can be done by adding mandatory
attribute to slave class constructor, but this is even worse(for me)
than using lock.
Please show me more clear way to make this slave to master link.
PS Sorry for my English.
I try make some weird thing. I want to get from code like this:
class master:
...
class slave:
...
m = master()
s = m.slave()
s.master is m
Last expression must be true. I want link "master" to be set
automatically by master object while creating slave object. Additional
requirement - "master" link must be available for constructor of slave
object.
Best what I can get is:
import functools
from weakref import WeakKeyDictionary
from threading import RLock
class meth_wrap(object):
def __init__(self, func):
object.__init__(self)
self.func = func
functools.update_wrapper(self, func, updated=())
class lazy_attr(meth_wrap):
def __get__(self, obj, type=None):
if obj is None:
return self
val = self.func(obj)
setattr(obj, self.__name__, val)
return val
class slave_mixin(object):
@lazy_attr
def master(self):
m = slave_gen._unbound_master
assert m is not None, '"Slave" object can\'t find master link.
Is it was correctly created? obj:%s' % repr(self)
return m
class slave_gen(meth_wrap):
_storage = WeakKeyDictionary()
# ИÑпользуетÑÑ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð¾
_unbound_master = None
_lock = RLock()
def __get__(self, mobj, type=None):
if mobj is None:
return self.func
d = {
'm': mobj,
'w': self}
obj = self.delay_init()
self._storage[obj] = d
functools.update_wrapper(obj, self.func, updated=())
return obj
class delay_init(object):
def __call__(self, *args, **kw_args):
d = slave_gen._storage[self]
slave_gen._lock.acquire()
try:
slave_gen._unbound_master = d['m']
obj = d['w'].func(*args, **kw_args)
obj.master = d['m']
slave_gen._unbound_master = None
finally:
slave_gen._lock.release()
return obj
def __getattr__(self, attr):
d = slave_gen._storage[self]
return getattr(d['m'], attr)
def __setattr__(self, attr, val):
d = slave_gen._storage[self]
return setattr(d['m'], attr, val)
class Master(object):
@slave_gen
class Slave(slave_mixin):
def __init__(self):
slave_mixin.__init__(self)
print 'Slave.__init__: self.master: ', self.master
if __name__ == '__main__':
m = Master()
s = m.Slave()
print 's.master: ', s.master
It works, by looking little weird... and I can't find way to escape from
using lock at object creation phase. It can be done by adding mandatory
attribute to slave class constructor, but this is even worse(for me)
than using lock.
Please show me more clear way to make this slave to master link.
PS Sorry for my English.