[Python-ideas] functools.lru_cache manual cache modification

Nick Coghlan ncoghlan at gmail.com
Tue Dec 2 13:57:07 CET 2014

On 2 December 2014 at 08:41, Cameron Simpson <cs at zip.com.au> wrote:
> On 01Dec2014 17:34, Constantin Berhard <constantin at exxxtremesys.lu> wrote:
>> One strength of the functools.lru_cache lies in caching results of calls
>> initiated by the function itself (i.e. recursive call results).
>> However because of the exception, the intermediate results from the tail
>> recursion don't end up in the cache, if my tail call optimization is
>> used together with lru_cache.
>> So I would like to be able to manually add argument-result pairs in the
>> cache. A manual lookup is not needed for my purpose, but I propose that
>> there should be methods to
>> 1. add argument-result pairs to the cache
>> 2. lookup if there is a result for given arguments
>> 3. lookup the result for given arguments if it exists (exception thrown
>> otherwise)
>> 4. invalidate specific cache entries (at the moment you can only
>> invalidate the cache as a whole through func.cache_clear())
>> What do you think?
> I'm kind of +1 on this, but I'd be for a different exposure. Let lru_cache
> expose a mapping of the cache. Once you have that mapping, expecially if it
> is just a dict, everything else comes for free.
> In fact, I'd advocate moving the LRU cache supporting object off into
> collections and building functools.lru_cache on top of that. Use case: I had
> to write my own LRU cache bcause I wasn't just wrapping a function. Having
> that available as a standalone object from collections which looked like a
> lossy mapping (i.e.  things vanish from the mapping when the cache
> overflows) would be immensely useful.

As far as I'm aware, this is actually a deliberate design decision.
There are so many degrees of freedom in designing a cache API that
without constrainting the usage model it's really quite difficult to
come up with a flexible abstraction that's easier to use than just
building your own custom caching class.

And once you expose the underlying mapping in functools.lru_cache
itself, it hugely constraints the internal implementation of that
cache (since you just made a whole lot of things that are currently
implementation details part of the public API).

So collections.OrderedDict provides the raw building block needed to
implement an LRU cache, while functools.lru_cache applies that
building block to a particular use case.

It's OK if folks with needs that don't quite fit the standard idiom
write their own custom class to handle it - that makes it possible to
keep the standard tools simple to handle the standard cases, while
folks with different needs can just write something specifically
tailored to their situation, rather than trying to learn and configure
a more generic API.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list