stouputils.decorators.simple_cache module#

ALL_CACHES: list[dict[Any, Any]] = [{('Stoupy51', 'stouputils', 2): ['latest', '26.0.2', '26.0.1', '26.0.0', '1.31.0', '1.30.1', '1.29.6', '1.28.1', '1.27.1', '1.26.4', '1.25.0', '1.24.13', '1.23.2', '1.22.3', '1.21.4', '1.20.4', '1.19.5', '1.18.6', '1.17.0', '1.16.3', '1.15.1', '1.14.3']}][source]#

Registry of every cache dict created by simple_cache(). Call clear_simple_caches() to clear all of them at once.

MISSING: Any = <object object>[source]#

Sentinel telling a cache miss apart from a cached None, so a lookup costs one dict access instead of two.

KWARGS_MARKER: tuple[object] = (<object object>,)[source]#

Separator inserted between args and kwargs by the “hash” method. Being a unique object, it keeps f(1, b=2) from colliding with f(1, ("b", 2)).

clear_simple_caches() None[source]#

Clear every cache created by simple_cache().

Useful for long-lived processes that run the same code on changing state: call this at the start of each cycle so cached results (and skipped side effects) from a previous cycle can’t leak into the next one.

Examples

>>> @simple_cache
... def count_calls(x: int, _calls: list[int] = []) -> int:
...     _calls.append(x)
...     return len(_calls)
>>> count_calls(1), count_calls(1)
(1, 1)
>>> clear_simple_caches()
>>> count_calls(1)
2
simple_cache(
func: Callable[..., T],
*,
method: Literal['hash', 'str', 'pickle'] | Callable[[tuple[Any, ...], dict[str, Any]], Any] = 'hash',
) Callable[..., T][source]#
simple_cache(
func: None = None,
*,
method: Literal['hash', 'str', 'pickle'] | Callable[[tuple[Any, ...], dict[str, Any]], Any] = 'hash',
) Callable[[Callable[..., T]], Callable[..., T]]

Decorator that caches the result of a function based on its arguments.

The default hash method is the fastest since it uses the arguments themselves as key, at the cost of two restrictions. It requires every argument to be hashable, and it shares one entry between equal keys such as 1, 1.0 and True. Switch to the str method for unhashable arguments, and to the pickle method for complex objects needing an exact key. The caching method is resolved once at decoration time, so an invalid one raises immediately instead of on first call.

Parameters:
  • func (Callable[..., T] | None) – Function to cache

  • method (Literal["hash", "str", "pickle"]) – The method to use for caching, or a callable building the key.

Examples

>>> @simple_cache
... def test1(a: int, b: int) -> int:
...     return a + b
>>> @simple_cache(method="str")
... def test2(a: int, b: int) -> int:
...     return a + b
>>> test2(1, 2)
3
>>> test2(1, 2)
3
>>> test2(3, 4)
7

Cache a recursive function:

>>> @simple_cache
... def factorial(n: int) -> int:
...     return n * factorial(n - 1) if n else 1
>>> factorial(10)   # no previously cached result, makes 11 recursive calls
3628800
>>> factorial(5)    # no new calls, just returns the cached result
120
>>> factorial(12)   # two new recursive calls, factorial(10) is cached
479001600

The default hash method uses the arguments themselves as key, so the str method is needed for unhashable ones:

>>> @simple_cache
... def test4(a: list[int], b: int) -> int:
...     return sum(a) + b
>>> test4([1], 2)
Traceback (most recent call last):
TypeError: ...unhashable type: 'list'...
>>> @simple_cache(method="str")
... def test5(a: list[int], b: int) -> int:
...     return sum(a) + b
>>> test5([1], 2)
3

Prevent a function from running more than once regardless of arguments:

>>> @simple_cache(method=lambda x, y: 1)
... def execute_one_time() -> None:
...     print("Executed!")
>>> _ = [execute_one_time() for _ in range(3)]
Executed!

An unknown method is rejected right away:

>>> @simple_cache(method="json")
... def test3() -> None: ...
Traceback (most recent call last):
ValueError: Invalid caching method 'json'...