title: Caching the results of a method
body: <p>For a project, I would like to cache the results computed by a method.
  Some constraints:</p>
  
  <ul>
  <li>I can't use Python3</li>
  <li>I can't use 3rd party modules</li>
  </ul>
  
  <p>What I've come up so far is this:</p>
  
  <pre><code>def cached_method(fun):
      """A memoize decorator for class methods."""
      @functools.wraps(fun)
      def get(self, *args, **kwargs):
          """Return the value if cached.
          Get it, cache it and return it if not.
          """
          try:
              self._cache[fun]
          except AttributeError:
              self._cache = {}
          except KeyError:
              pass
  
          return self._cache.setdefault(fun, {}).setdefault((args, tuple(kwargs.items())), fun(self, *args, **kwargs))
  
      return get
  </code></pre>
  
  <p>However, there's something wrong. In fact, using a minimal example, such as this:</p>
  
  <pre><code>class TestClass(object):
  
      @cached_method
      def method(self, p_arg):
          print 'sentinel'
          return p_arg
  
  sut = TestClass()
  sut.method(2)
  sut.method(2)
  </code></pre>
  
  <p>You'll see the method is called twice ('sentinel' is printed twice)</p>
  
  <p>Inspecting it via PDB I can't see what the problem is, given the second time <code>_cache</code> is effectively containing all what's needed.</p>
  
  <p><strong>Edit</strong></p>
  
  <p>As pointed out in the comments, the issue is with <code>setdefault</code> which calls the argument passed as default (the second) regardless whether the key is found or not.</p>
  
  <p>To fix that problem, replace the <code>return</code> line above with:</p>
  
  <pre><code>results = self.cache.setdefault(fun, {})
  
  try:
      ret = results[(args, tuple(kwargs.items()))]
  except KeyError:
      ret = results[(args, tuple(kwargs.items()))] = fun(self, *args, **kwargs)
  
  return ret
  </code></pre>