import threading import time import os class Proxy(object): def __init__(self, instance=None, get_instance=None): class Foo: pass # hack to create an instant namespace self.__dict__['_vars'] = Foo() assert(instance is None or get_instance is None) assert(instance is not None or get_instance is not None) if get_instance is not None: def set_instance(self): if self._vars.instance is None: self._vars.instance = get_instance() self._vars.instance = None self._vars.set_instance = set_instance elif instance is not None: def set_instance(self): pass self._vars.instance = instance self._vars.set_instance = set_instance def __getattr__(self, key): if key == '_vars': return self.__dict__['_vars'] else: self._vars.set_instance(self) return getattr(self._vars.instance, key) def __setattr__(self, key, value): self._vars.set_instance(self) return getattr(self._vars.instance, key) # Inheriting from object defines some things that we need to proxy: # dir(object) # Override methods inherited from object: def __str__(self): self._vars.set_instance(self) return getattr(self._vars.instance, '__str__')() def __repr__(self): self._vars.set_instance(self) return 'Proxy for %s' % getattr(self._vars.instance, '__repr__')() # ...I don't know why these aren't funnelled through __getattr__ def __add__(self, x): self._vars.set_instance(self) return getattr(self._vars.instance, '__add__')(x) def Waiting(object): pass class BackgroundMethod(threading.Thread): def __init__(self, method, args, kwargs): threading.Thread.__init__(self) self.method = method self.args = args self.kwargs = kwargs self.return_value = Waiting def run(self): self.return_value = self.method(*self.args, **self.kwargs) def background(method): def wrapper(*args, **kwargs): x = BackgroundMethod(method, args, kwargs) x.start() return TransparentFuture(x) return wrapper class TransparentFuture(Proxy): def __init__(self, background_method): def get_instance(): if background_method.return_value == Waiting: background_method.join() return background_method.return_value Proxy.__init__(self, get_instance=get_instance) t0 = time.time() times = [] x = background(time.sleep)(1) y = background(os.system)('sleep 1.5') z = background(lambda a, b: a + b)(3, 7) times.append(time.time()) print 'x=', x # x= None times.append(time.time()) print 'y=', y # y= 0 times.append(time.time()) print 'z+1=', z+1 # z+1= 11 times.append(time.time()) for t in times: print t - t0 # 0.000727891921997 # 1.00506281853 # 1.50716495514