Function decorator that caches function results

Steven D'Aprano steve at REMOVETHIScyber.com.au
Sun Oct 9 11:56:02 CEST 2005


On Sat, 08 Oct 2005 15:20:12 +0200, Lasse Vågsæther Karlsen wrote:

> Ok, so I thought, how about creating a decorator that caches the 
> function results and retrieves them from cache if possible, otherwise it 
> calls the function and store the value in the cache for the next invokation.
> 
> This is what I came up with so far:
> 
> 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.



> The solution would have to consider fibonacci(50) and fibonacci(idx = 
> 50) as the same call and thus retrieve the second one from the cache.

In general, you probably can't do that without lots and lots of really
clever code searching through the function argument lists. If you know
that your function will always have the same keyword, then you can do
something like this:

        if args in cache:
            return cache[args]
        elif kwargs.keys() == "idx":
            return cache[kwargs["idx"]]

but that's a special case and you really don't want to do it *wink*

Otherwise, just accept that you may be caching multiple copies of the same
data, and do something like this:

        if args in cache:
            return cache[args]
        elif kwargs.items() in cache:
            return cache[kwargs.items()]

with the appropriate changes to the rest of the code.

You may also find that you could get a slight performance increase by
using the idiom 

try:
    return cache[args]
except:
    # calculate the result and store it in the cache.
    
instead of testing for membership. As always, timing some test functions
is your friend...



-- 
Steven.




More information about the Python-list mailing list