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:
from functools import wrapsfrom 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 functionprint(fibonacci(10)) # This will cache the result of the function
# Call the function againprint(fibonacci(10)) # This will return the cached result
# Update the cacheprint(fibonacci.cache_update(10)) # This will update the cache with the new result