anfema_django_utils.caching.cached_call
- cached_call(maxsize=128)
Decorator to wrap a function with a memoizing callable similar to the
functools.lru_cache()
decorator.You can use the decorator on lambdas, functions, methods, classmethods and staticmethods.
Note
Some callables may not be cachable in certain implementations of Python. For example, in CPython, built-in functions defined in C provide no metadata about their arguments.
Unlike
functools.lru_cache()
,cached_call()
provides the possibility to invalidate the cache for a specific call. The cache keeps references to the arguments and return values until they age out of the cache or until the cache is cleared viaclear_call()
orclear()
.To cache the result
cached_call()
uses the positional and keyword arguments and creates a hash value using the super_hash library. Hence, the positional and keyword arguments must be hashable with super_hash.If a method is cached, the
self
instance attribute is included in the cache. The same applies for thecls
attribute of a cachedclassmethod
.Distinct argument patterns does not result in separate cache entries, i.e.
f(a=1, b=2)
andf(b=2, a=1)
have the same cache entry. You should consider that arguments with a default value are taken also into account for caching. I.e. a function with a signaturef(a=None, b=True)
results in the same cache entry for the callsf(a=None)
andf(b=True)
. For methods, the callsFoo.bar(foo, *args, **kwargs)
andfoo.bar(*args, **kwargs)
will be considered the same and thus also result in the same cache entry.If user_function is specified, it must be a callable. This allows the
cached_call()
decorator to be applied directly to a user function, leaving the maxsize at its default value of 128:@cached_call(maxsize=32) def foo(*args): ... @cached_call def bar(*args): ...
If maxsize is set to
None
, the cache can grow without bound.The original underlying callable is accessible through the
__wrapped__
attribute.To clear a cache entry for a specific call you can use
clear_call()
with passing the arguments, for which call the cache entry shall be cleared. To reset the complete cache, callclear()
:@cached_call def foo(*args): return uuid.uuid4() >>> foo(1) # returns a new UUID UUID('9306c73b-ff0a-439b-901c-c347ac548904') >>> foo(1) # returns the cached value UUID('9306c73b-ff0a-439b-901c-c347ac548904') >>> foo(2) # returns a new UUID UUID('2e7ca126-7943-46cc-a81b-0fbd30b07969') >>> foo.clear_call(1) # clear the cache only for the call foo(1) >>> foo(1) # returns a new UUID UUID('3b3cc8b2-6ec5-4582-8314-926aa625b1fc') >>> foo(2) # returns the cached value UUID('2e7ca126-7943-46cc-a81b-0fbd30b07969') >>> foo.clear() # clear the cache for all calls