Clear an lru_cache when its source rule changes

Clear an lru_cache when its source rule changes

By Batu

functools.lru_cache keys results from function arguments, not from mutable data the function happens to read. In this example, shipping_cost("standard") reads the rates dictionary but accepts only service as its argument. After changing rates["standard"] from 5 to 7, the cached call still returns 5 because its key is unchanged.

The rule-update boundary is therefore the right place to call the wrapper's cache_clear() method. set_rate() updates the dictionary and immediately clears every cached shipping result. A later call recomputes the standard price and returns 7. cache_info() confirms that the final call created one cache miss after the clear; the example prints only stable business results rather than implementation counters.

This pattern is appropriate when all cached outputs depend on one small, mutable rule set. cache_clear() invalidates the entire cache, not only the changed service, so it can be unnecessarily expensive for a large cache or frequent updates. In that case, include an immutable rule version in the cached function's arguments, or use a cache that supports targeted invalidation. The cache also does not synchronize a multi-step external update protocol; protect shared mutable rules with appropriate application-level concurrency control when threads can update them.

AI assistance was used to draft this article.

from functools import lru_cache

rates = {"standard": 5, "express": 12}


@lru_cache(maxsize=8)
def shipping_cost(service: str) -> int:
    return rates[service]


def set_rate(service: str, amount: int) -> None:
    rates[service] = amount
    shipping_cost.cache_clear()


before_change = shipping_cost("standard")
rates["standard"] = 7
stale_value = shipping_cost("standard")
set_rate("standard", 7)
after_clear = shipping_cost("standard")

assert before_change == 5
assert stale_value == 5
assert after_clear == 7
assert shipping_cost.cache_info().misses == 1
print(before_change)
print(stale_value)
print(after_clear)

Expected stdout:

5
5
7

Sources

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic