I frequently find myself adding "just in time" (JIT) object creation to avoid wasting cycles on objects that are never used. This class enables JIT object creation by basically currying the __init__ method.
The object is instianted only when an attribute is got or set. Then automatic delegation is used to front for the object (see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52295)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
class JIT: ''' JIT is a class for Just In Time instantiation of objects. Init is called only when the first attribute is either get or set. ''' def __init__(self, klass, *args, **kw): ''' klass -- Class of objet to be instantiated *args -- arguments to be used when instantiating object **kw -- keywords to be used when instantiating object ''' self.__dict__['klass'] = klass self.__dict__['args'] = args self.__dict__['kw'] = kw self.__dict__['obj'] = None def initObj(self): ''' Instantiate object if not already done ''' if self.obj is None: self.__dict__['obj'] = self.klass(*self.args, **self.kw) def __getattr__(self, name): self.initObj() return getattr(self.obj, name) def __setattr__(self, name, value): self.initObj() setattr(self.obj, name, value) class TestIt: def __init__(self, arg, keyword=None): print 'In TestIt.__init__() -- arg: %s, keyword=%s' % (arg, keyword) def method(self): print 'In TestIt.method().' def oldWay(): # Create t whether or not it gets used. t = TestIt('The Argument', keyword='The Keyword') def main(): # JIT refactored t = JIT(TestIt, 'The Argument', keyword='The Keyword') print 'Not intstaintiated yet.' # TestIt object instantiated here. t.method() if __name__ == '__main__': main() # OUTPUT: # Not intstaintiated yet. # In TestIt.__init__() -- arg: The Argument, keyword=The Keyword # In TestIt.method().
Remember the idiom "First make it work, then if it is not fast enough make it work faster." One way to make it work faster is to avoid creating objects that never get used. This can be difficult to do however without a major re-design in some cases.
This recepe is intended to bridge that gap. Refactoring with the JIT class becomes cake-work; just replace object creation with the JIT proxy.
The proxy code does have an overhead and will actually slow the code down if the object is actually created. It should only be used for rarely needed objects.
It would be really cool if the proxy could replace its self with the actual object when the object was created. Any ideas?