How to Invalidate Cache When Arguments Change in Python

A memoization decorator that caches function results keyed by arguments, automatically invalidating when inputs change.

Medium Python 3.9+ Aug 9, 2026 Functions & basics 16 views 0 copies

Python code

24 lines
Python 3.9+
from functools import wraps

def memoize(func):
    cache = {}
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, tuple(sorted(kwargs.items())))
        if key not in cache:
            cache[key] = func(*args, **kwargs)
        return cache[key]
    
    return wrapper

@memoize
def expensive_calculation(x, y):
    print(f"Calculating for ({x}, {y})...")
    return x * y + x + y

if __name__ == "__main__":
    print(expensive_calculation(2, 3))  # Calculates
    print(expensive_calculation(2, 3))  # Cached
    print(expensive_calculation(3, 2))  # New args, calculates
    print(expensive_calculation(2, 3))  # Cached again

Output

stdout
Calculating for (2, 3)...
11
11
Calculating for (3, 2)...
17
11

How it works

The @wraps decorator preserves the original function's metadata (name, docstring) so debugging stays clean. The cache key is built from args and sorted kwargs.items(), which ensures identical calls with different argument orders hit the same cache entry. When arguments change, the key differs, causing a recomputation — this is the automatic invalidation mechanism. The cache persists for the lifetime of the wrapped function, making it ideal for expensive, pure computations.

Common mistakes

  • Using mutable objects as arguments (like lists) — they can't be hashed as cache keys
  • Forgetting to sort kwargs items, causing redundant cache misses for swapped keyword arguments
  • Not using @wraps, losing the original function's name and docstring

Variations

  1. Use `functools.lru_cache(maxsize=None)` for a built-in, thread-safe memoization decorator
  2. Add a TTL (time-to-live) parameter to expire cache entries after a set duration

Real-world use cases

  • Caching database query results in a dashboard API to avoid repeated expensive lookups.
  • Memoizing recursive Fibonacci or combinatorial functions in financial risk simulations.
  • Storing parsed configurations in a microservice so repeated reads don't hit disk or network.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Functions & basics

Related tutorials and quizzes for this topic.