Package: astrocache
astrocacheDurable memoization that automatically refreshes as you update your source code.InstallationRequires Python >= 3.9.python3 -m pip install astrocacheWhat is this?This library provides disk-backed memoization for Python functions with a
surprisingly useful twist: the cache is sensitive not only to your function's inputs,
but also to itsimplementation(represented by its abstract syntax tree or AST).If you're unfamiliar with memoization, check out theWikipedia
pageandfunctools.cachefor in-depth explanations.AST-sensitive memoizationimportastrocache@astrocache.cache()deffoo(a,b):returnslow_fn(a)+bThis creates a disk-backed cache forfoo, which preventsfoofrom performing the
same work more than once for a given input. So far, this is pretty standard; many
other libraries offer the same thing.But what if you change the behavior offoo?@astrocache.cache()deffoo(a,b):returnslow_fn(a)+b*2Your cache entries are no longer valid.Luckily,astrocacheis aware of this. It will create new cache entries for the new
version offoo.This treatment extends recursively to any function called byfooas well. In this
case, changes toslow_fn(and to functions called byslow_fn, etc) will also
invalidate cache entries forfoo.How does it work?Astrocache creates a fingerprint of your function's abstract syntax tree (AST)
using theastmodule from the standard
library.When your function is called, this fingerprint is combined with the provided
arguments to create a cache key.How is this useful?This is particularly useful in highly interactive workflows, e.g. during rapid
iteration or in a notebook setting. Many libraries provide some form of memoization,
but none (as far as I know) manage this kind of cache invalidation for you.As an example, imagine you're rapidly iterating on a script that processes data in
several expensive steps, or hits a usage-capped external API.Memoization could certainly make you more productive, but you'd have to remember to
clear the various cache entries as you updated your code.This library automates this for you, allowing you to take advantage of memoization
without needing to worry about clearing the cache.LimitationsReferenced functionsThere is a caveat regarding AST inspection of functions that are referenced, but not
invoked. Example:importastrocachedefbar(a):returna+1@astrocache.cache()deffoo(x):returnbaz(bar)Here,baris referenced (passed as an argument), but not invoked, byfoo.Functions appearing within your cached function are only included in the AST
fingerprint if your cached function does any of these:Calls the referenced functionReceives the referenced function as an argumentContains the definition of the referenced functionHere are some examples to illustrate this:✅ Calling a function@astrocache.cache()deffoo(referenced_function):# referenced_function will be includedreferenced_function(1)✅ Receiving the function as an argument@astrocache.cache()deffoo(referenced_function):# referenced_function will be includedfoo(referenced_function)✅ Defining a function within the cached function@astrocache.cache()deffoo():# referenced_function will be includeddefreferenced_function():return1foo(referenced_function)❌ Assigning a function from outer scope to a variable (only)@astrocache.cache()deffoo():# referenced_function will NOT be includedfoo=referenced_function❌ Passing a function from outer scope to a called function (only)@astrocache.cache()deffoo():# referenced_function will NOT be includedfoo(referenced_function)Related projectsjoblib