Skip to content

General function cache decorator

Sometimes you need to cache the result of a function to avoid recomputing it every time. You can use a decorator to cache the result of a function in Python.

here’s a simple example of a cache decorator:

cache_decorator.py
from functools import wraps
from typing import Callable, List, Optional
from django.core.cache import caches
def _generate_cache_key(func, args, kwargs, exclude):
func_args = func.__code__.co_varnames
named_args = {k: v for k, v in zip(func_args, args)}
named_args.update(kwargs)
if exclude:
for key in exclude:
named_args.pop(key, None)
return f"{func.__module__}.{func.__name__}.{named_args}"
def _get_cache(cache_backend_name: str, default_cache_backend_name: str = "default"):
if cache_backend_name in caches:
return caches[cache_backend_name]
return caches[default_cache_backend_name]
def _set_cache(cache, key, value, timeout, skip_cache_on=[]):
if value not in skip_cache_on:
cache.set(key, value, timeout)
return value
def cache_decorator(cache_backend_name: str = "default", timeout: int = 60, exclude: Optional[List] = [],
fallback_cache_backend_name: str = "default", skip_cache_on: Optional[List] = []) -> Callable:
"""
Decorator to cache the results of a function
:param cache_name: The name of the cache backend to use
:param timeout: The timeout of the cache
:param exclude: List of arguments to exclude from the cache key
:param fallback_cache_backend_name: The name of the cache backend to use in case of cache backend not found
:param skip_cache_on: List of values to skip caching
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = _generate_cache_key(func, args, kwargs, exclude)
cache = _get_cache(cache_backend_name, fallback_cache_backend_name)
value = cache.get(key)
if value is None:
value = func(*args, **kwargs)
return _set_cache(cache, key, value, timeout, skip_cache_on)
return value
def cache_update(*args, **kwargs):
key = _generate_cache_key(func, args, kwargs, exclude)
cache = _get_cache(cache_backend_name, fallback_cache_backend_name)
value = func(*args, **kwargs)
return _set_cache(cache, key, value, timeout, skip_cache_on)
wrapper.cache_update = cache_update
return wrapper
return decorator

You can use this decorator to cache the result of a function like this:

from cache_decorator import cache_decorator
@cache_decorator(cache_backend_name="default", timeout=60)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
# Call the function
print(fibonacci(10)) # This will cache the result of the function
# Call the function again
print(fibonacci(10)) # This will return the cached result
# Update the cache
print(fibonacci.cache_update(10)) # This will update the cache with the new result