title: Setting a get/set property in a python memoization decorator class
body: <p>I have created a decorator memoization class that I am actively using for cache my calls.  There are already many excellent suggestions on how to implement python memoization.  </p>
  
  <p>The class that I have created currently uses get and set method calls to set the cacheTimeOut.  They are called <code>getCacheTimeOut()</code> and <code>setCacheTimeOut()</code>.  While this is an adequate solution.  I was hoping to use the <code>@property</code> and <code>@cacheTimeOut.setter</code> decorators to enable the functions to be called directly as for example <code>cacheTimeOut=120</code> </p>
  
  <p>The problem is in the details.  I do not know how to make these properties accessible in the <code>__get__</code> method.  The <code>__get__</code> method assigns the different function calls defined within the class to functions.partial.  </p>
  
  <p>Here is my script example designed for Python 2.7</p>
  
  <pre><code>import time
  from functools import partial
  import cPickle
  
  class memoize(object):
      def __init__(self, func):
          self.func = func
          self._cache = {}
          self._timestamps = {}
          self._cacheTimeOut = 120
          self.objtype = None
  
      def __new__(cls, *args, **kwargs):
          return object.__new__(cls,*args, **kwargs)
  
      def __get__(self, obj, objtype=None):
      """Used for object methods where decorator has been placed before methods."""
          self.objtype = objtype
          fn = partial(self, obj)
          fn.resetCache = self.resetCache
          fn.getTimeStamps = self.getTimeStamps
          fn.getCache = self.getCache
          fn._timestamps = self._timestamps
          fn.setCacheTimeOut = self.setCacheTimeOut
          fn.getCacheTimeOut = self.getCacheTimeOut
          return fn
  
      def __argsToKey(self, *args, **kwargs):
          args = list(args)
  
          for x, arg in enumerate(args):    # remove instance from
              if self.objtype:
                   if isinstance(arg, self.objtype):
                       args.remove(arg)
  
          str = cPickle.dumps(args, 1)+cPickle.dumps(kwargs, 1)
  
          return str
  
      def __call__(self, *args, **kwargs):
          """Main calling function of decorator."""
           key = self.__argsToKey(*args, **kwargs)    
           now = time.time()    # get current time to query for key
           if self._timestamps.get(key, now) &gt; now:    
               return self._cache[key]
           else:
               value = self.func(*args, **kwargs)
               self._cache[key] = value
               self._timestamps[key] = now + self._cacheTimeOut
           return value
  
      def __repr__(self):
          '''Return the function's docstring.'''
          return self.func.__doc__
  
      def resetCache(self):
          """Resets the cache.  Currently called manually upon request."""
          self._cache = {}
          self._timestamps = {}
  
      def getCacheTimeOut(self):
      """Get the cache time out used to track stale data."""
          return self._cacheTimeOut
  
      def setCacheTimeOut(self, timeOut):
      """Set the cache timeout to some other value besides 120.  Requires an integer     value.  If you set timeOut to zero you are ignoring the cache"""
          self._cacheTimeOut = timeOut
  
      def getCache(self):
      """Returns the cache dictionary."""
          return self._cache
  
      def getTimeStamps(self):
      """Returns the encapsulated timestamp dictionary."""
          return self._timestamps
  
      @property
      def cacheTimeOut(self):
      """Get cacheTimeOut."""
          return self._cacheTimeOut
  
      @cacheTimeOut.setter
      def cacheTimeOut(self, timeOut):
      """Set cacheTimeOut."""
          self._cacheTimeOut = timeOut
  
  memoize
  def increment(x):
      increment.count+=1
      print("increment.count:%d, x:%d"%(increment.count, x))
      x+=1
      return x
  
  
  increment.count = 0   # Define the count to track whether calls to increment vs cache
  
  
  class basic(object):
      def __init__(self):
          self.count = 0
  
      @memoize
      def increment(self, x):
          self.count+=1
          print("increment.count:%d, x:%d"%(increment.count, x))
          x+=1
          return x
  
  
  def main():
      print increment(3)
      print increment(3)
  
      # What I am actually doing
      print increment.getCacheTimeOut()  # print out default of 120
      increment.setCacheTimeOut(20)      # set to 20
      print increment.getCacheTimeOut()  # verify that is has been set to 120
  
      # What I would like to do and currently does not work
      print increment.cacheTimeOut
      # Assign to property
      increment.cacheTimeOut = 20
  
  
      myObject = basic()
      print myObject.increment(3)
      print myObject.count
      print myObject.increment(3)
      print myObject.count
      print myObject.increment(4)
      print myObject.count
  
  
  
  ####### Unittest code. 
  import sys
  import time
  import unittest
  from memoize import memoize
  
  class testSampleUsages(unittest.TestCase):
  # """This series of unit tests is to show the user how to apply memoize calls."""
      def testSimpleUsageMemoize(self):
          @memoize
          def increment(var=0):
              var += 1
              return var
  
          increment(3)
          increment(3)
  
      def testMethodBasedUsage(self):
          """Add the @memoize before method call."""
          class myClass(object):
              @memoize
              def increment(self,var=0):
                  var += 1
                  return var
  
              @memoize
              def decrement(self, var=0):
                  var -=1
                  return var
  
          myObj = myClass()
          myObj.increment(3)
          myObj.increment(3)
          myObj.decrement(6)
          myObj.decrement(6)
  
      def testMultipleInstances(self):
          @memoize
          class myClass(object):
              def __init__(self):
                 self.incrementCountCalls = 0
                 self.decrementCountCalls = 0
                 self.powCountCall = 0
  
              # @memoize
              def increment(self,var=0):
                  var += 1
                  self.incrementCountCalls+=1
                  return var
  
              # @memoize
              def decrement(self, var=0):
                  self.decrementCountCalls+=1
                  var -=1
                  return var
  
              def pow(self, var=0):
                  self.powCountCall+=1
                  return var*var
  
  
          obj1 = myClass()   # Memoizing class above does not seem to work.  
          obj2 = myClass()
          obj3 = myClass()
  
          obj1.increment(3)
          obj1.increment(3)
          #obj2.increment(3)
          #obj2.increment(3)
          #obj3.increment(3)
          #obj3.increment(3)
  
          obj1.pow(4)
          obj2.pow(4)
          obj3.pow(4)
  </code></pre>