Slave to master auto linking.

Богун Дмитрий vugluskr at vugluskr.org.ua
Sun Nov 13 19:58:44 EST 2011


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.

-- 
Богун Дмитрий aka vugluskr




More information about the Python-list mailing list