Saturday, October 10, 2009

Python Function Decorators 3: Input Based Caching

Below you can find an input based cache system implemented as a Python function decorator:

########################################################################
class InputBasedCachedMethod(object):
    """caches the result of a class method inside the instance based on the input
    """
    
    
    
    #----------------------------------------------------------------------
    def __init__(self, method):
        # record the unbound-method and the name
        #print "running __init__ in InputBasedCachedMethod"
        
        self._method = method
        self._name = method.__name__
        self._obj = None
        
        
        
    #----------------------------------------------------------------------
    def __get__(self, inst, cls):
        """use __get__ just to get the instance object
        """
        #print "running __get__ in InputBasedCachedMethod"
        
        self._obj = inst
        if not hasattr( self._obj, self._name + "._outputData" ):
            #print "creating the data"
            setattr ( self._obj, self._name + "._outputData", list() )
            setattr ( self._obj, self._name + "._inputData", list() )
            #print "finished creating data"
            
        return self
    
    
    
    #----------------------------------------------------------------------
    def __call__(self, *args, **keys):
        """for now it uses only one argument
        """
        #print "running __call__ in InputBasedCachedMethod"
        
        outputData = getattr( self._obj, self._name + "._outputData" )
        inputData = getattr( self._obj, self._name + "._inputData" )
        
        # combine args and keys
        argsKeysCombined = list()
        argsKeysCombined.append( args )
        argsKeysCombined.append( keys )
        
        if (not argsKeysCombined in inputData) or outputData == None:
            #print "calculating new data"
            data = self._method(self._obj, *args, **keys)
            inputData.append( argsKeysCombined )
            outputData.append( data )
            setattr( self._obj, self._name + "._inputdata", inputData )
            setattr( self._obj, self._name + "._outputData", outputData )
            
            return data
        else:
            #print "returning cached data"
            return outputData[ inputData.index( argsKeysCombined ) ]
    
    
    
    #----------------------------------------------------------------------
    def __repr__(self):
        """Return the function's repr
        """
        #print "running __repr_ in InputBasedCachedMethod"
        objectsRepr = str(self._obj)
        objectsName = objectsRepr.split(' ')[0].split('.')[-1]
        cachedObjectsRepr = ''
        return cachedObjectsRepr


Edit 1: Edited the cache class, now it supports both arguments and keyword arguments, and I didn't delete the lines that has print commands, so you can uncomment the lines to see which one of the methods runs when

1 comment:

GuildWars2Items said...

Diablo 3 Gold someone who makes you believe that there really is good in the world, someone who makes you laugh until you can't stop Buy Diablo 3 Gold, someone who changes your life just by being part of it Cheap Diablo 3 Gold, this is Forever Friendship

The past is gone and static. Nothing we can do will change it.scarlet blade gold, the future is before us and dynamic. Everything we do will affect it rs gold, You laugh at mescarlet blade gold for being different , but I laugh at you for being the same.