Cache any function (with its arguments)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import cPickle as pickle
import md5

def cache_function(length):
    """
    A variant of the snippet posted by Jeff Wheeler at
    http://www.djangosnippets.org/snippets/109/
    
    Caches a function, using the function and its arguments as the key, and the return
    value as the value saved. It passes all arguments on to the function, as
    it should.
    
    The decorator itself takes a length argument, which is the number of
    seconds the cache will keep the result around.
    
    It will put in a MethodNotFinishedError in the cache while the function is
    processing. This should not matter in most cases, but if the app is using
    threads, you won't be able to get the previous value, and will need to
    wait until the function finishes. If this is not desired behavior, you can
    remove the first two lines after the ``else``.
    """
    def decorator(func):
        def inner_func(*args, **kwargs):
            from django.core.cache import cache
            
            raw = [func.__name__, func.__module__, args, kwargs]
            pickled = pickle.dumps(raw, protocol=pickle.HIGHEST_PROTOCOL)
            key = md5.new(pickled).hexdigest()
            value = cache.get(key)
            if cache.has_key(key):
                return value
            else:
                # This will set a temporary value while ``func`` is being
                # processed. When using threads, this is vital, as otherwise
                # the function can be called several times before it finishes
                # and is put into the cache.
                class MethodNotFinishedError(Exception): pass
                cache.set(key, MethodNotFinishedError(
                    'The function %s has not finished processing yet. This \
value will be replaced when it finishes.' % (func.__name__)
                ), length)
                result = func(*args, **kwargs)
                cache.set(key, result, length)
                return result
        return inner_func
    return decorator

More like this

  1. Cache Any Function by jeffwheeler 7 years, 1 month ago
  2. Language aware cache decorator by bartTC 4 years, 11 months ago
  3. Decorator cache handler per view by guicifuentes 5 years, 7 months ago
  4. Run and cache only one instance of a heavy request by farnsworth 3 years, 8 months ago
  5. Making the HTTP object available globally across the app by sleepycal 3 years, 2 months ago

Comments

trbs (on May 1, 2008):

suggesting a try-except block around:

import cPickle as pickle

like such:

try:
    import cPickle as pickle
except ImportError:
    import pickle

To allow for fallback on pickle when cPickle is not accessible.

#

cazzerson (on July 27, 2008):

I am getting an error when I use this...

Can't pickle : attribute lookup django_snippet_cache_function.MethodNotFinishedError failed

Thanks...

#

(Forgotten your password?)