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
selfinstance attribute is included in the cache. The same applies for theclsattribute 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