24. Function caching

Function caching allows us to cache the return values of a function depending on the arguments. It can save time when an I/O bound function is periodically called with the same arguments. Before Python 3.2 we had to write a custom implementation. In Python 3.2+ there is an lru_cache decorator which allows us to quickly cache and uncache the return values of a function.

Let’s see how we can use it in Python 3.2+ and the versions before it.

24.1. Python 3.2+

Let’s implement a Fibonacci calculator and use lru_cache.

from functools import lru_cache

def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

>>> print([fib(n) for n in range(10)])
# Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

The maxsize argument tells lru_cache about how many recent return values to cache.

We can easily uncache the return values as well by using:


24.2. Python 2+

There are a couple of ways to achieve the same effect. You can create any type of caching mechanism. It entirely depends upon your needs. Here is a generic cache:

from functools import wraps

def memoize(function):
    memo = {}
    def wrapper(*args):
        if args in memo:
            return memo[args]
            rv = function(*args)
            memo[args] = rv
            return rv
    return wrapper

def fibonacci(n):
    if n < 2: return n
    return fibonacci(n - 1) + fibonacci(n - 2)


Here is a fine article by Caktus Group in which they caught a bug in Django which occurred due to lru_cache. It’s an interesting read. Do check it out.