In the comment: Is there a decorator to simply cache function return values?
@gerrit points out a problem with using mutable, but hashable, objects to to a function with the functools.lru_cache
decorator:
If I pass a hashable, mutable argument, and change the value of the object after the first call of the function, the second call will return the changed, not the original, object. That is almost certainly not what the user wants.
From my understanding, assuming the __hash__()
function of the mutable objects is manually defined to hash the member variables (and not just using the object's id()
that is the default for custom objects), changing the argument object will change the hash, hence, a second call should to the lru_cache
decorated function should not utilize the cache.
If the __hash__()
function is defined correctly for the mutable argument(s), is there any unattended behavior that can arise from using mutable arguments to lru_cache
decorated functions?
My comment was wrong/misleading and does not relate to
lru_cache
, but to any attempt to create a caching function that works more generically.I was facing a need for a caching function that works for function that input and output
NumPy
arrays, which are mutable and not hashable. BecauseNumPy
arrays are not hashable, I could not usefunctools.lru_cache
. I ended up wroting something like this:In my first version, I had omitted the
copy.copy()
function (which should really becopy.deepcopy()
), which led to bugs if I changed the resulting value and then recalled the cached-function. After I added thecopy.copy()
functionality, I realised that I was hogging memory for some cases, primarily because my function counts objects, not total memory usage, which is non-trivial to do in general in Python (although should be easy if limited toNumPy
arrays). Therefore I added theNO_CACHE
andCLEAR_CACHE
keywords to the resulting function, which do what their names suggest.After writing and using this function, I understand there is more than one good reason for
functools.lru_cache
to work only for functions with hashable input arguments. Anyone needing a caching function that works with mutable arguments needs to be very careful.