Skip to content

Instantly share code, notes, and snippets.

@firdavsDev
Created August 23, 2024 13:35
Show Gist options
  • Save firdavsDev/604bff036cf8b644e35c3861a91bb87d to your computer and use it in GitHub Desktop.
Save firdavsDev/604bff036cf8b644e35c3861a91bb87d to your computer and use it in GitHub Desktop.
Python Function Caching
from functools import lru_cache, wraps
from time import monotonic
def lru_cache_with_ttl(maxsize=128, typed=False, ttl=60):
"""Least-recently used cache with time-to-live (ttl) limit."""
class Result:
__slots__ = ("value", "death")
def __init__(self, value, death):
self.value = value
self.death = death
def decorator(func):
@lru_cache(maxsize=maxsize, typed=typed)
def cached_func(*args, **kwargs):
value = func(*args, **kwargs)
death = monotonic() + ttl
return Result(value, death)
@wraps(func)
def wrapper(*args, **kwargs):
result = cached_func(*args, **kwargs)
if result.death < monotonic():
result.value = func(*args, **kwargs)
result.death = monotonic() + ttl
return result.value
wrapper.cache_clear = cached_func.cache_clear
return wrapper
return decorator
"""
Usage:
# Recalculate cached results after 5 seconds.
minut = 60
hour = 60 * minut
day = 24 * hour
@lru_cache_with_ttl(ttl=5*minut)
def expensive_function(a, b):
return a + b
"""
@firdavsDev
Copy link
Author

Benefits

  1. Short, easy to review, and no PyPI install necessary. Relies only on the Python standard library, 3.7+.
  2. No annoying ttl=10 parameter needed at all callsites.
  3. Does not evict all items at the same time.
  4. Key/value pairs actually live for the given TTL value.
  5. Stores only one key/value pair per unique (*args, **kwargs) even when items expire.
  6. Works as a decorator (kudos to the Javier Buzzi answer and Lewis Belcher answer).
  7. Is thread safe. IDK(
  8. Benefits from the C-optimizations of CPython from python.org and is compatible with PyPy.

More info:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment