Function decorator that caches function results

Paul Rubin http
Sun Oct 9 05:49:38 EDT 2005


Steven D'Aprano <steve at REMOVETHIScyber.com.au> writes:
> > def cache_function(fn):
> >      cache = {}
> >      def cached_result(*args, **kwargs):
> >          if args in cache:
> >              return cache[args]
> >          result = fn(*args, **kwargs)
> >          cache[args] = result
> >          return result
> >      return cached_result
> 
> I'm curious... where does cache live after you use cache_function to
> memoize some function? It doesn't appear to be an attribute of the newly
> memoized function, nor does it look like a global variable.

It's in the closure returned by cache_function.  cached_result doesn't
change the value of 'cache' (it only changes the boxed content),
cached_result finds it in the outer scope, so you can get away with
that in Python.  You couldn't do something like:

   def counter():
     n = 0
     def k():
       n += 1    # rebinds n, so Python thinks n is local, oops
       return n
     return k

Since k changes the value of n, Python thinks n is local to k, and
you get a NameError when you try to increment it the first time.
That you can't set the value of a closure variable is something of a
Python wart and is one of the things that makes me want a "local"
declaration in Python.

Closures are a Scheme idiom and Pythonistas tend to use class
instances instead, but both techniques are useful.



More information about the Python-list mailing list