@functools.lru_cache on a nested function

So I have, essentially, this:

import functools
def do_stuff(foo, bar):
    @functools.lru_cache(maxsize=None)
    def cmp_form(word):
        return word.strip().casefold()
    cmp_form.cache_clear()
[...]
[... main contents of do_stuff function ...]

The situation is more complex and the calculation being cached is more expensive, but that's the nutshell version. It's worth caching the result because it's expensive to calculate and the same values are used over and over in a nested loop. But multiple calls to do_stuff don't necessarily share any data and there's no point in letting the cache grow boundlessly over a long run (though there's a good argument to letting it grow boundlessly over a single call to do_stuff, because many many results might have to be cached, and this is both meaningful and helpful during that single run).

What I'm wondering is whether the call to cmp_form.cache_clear() is necessary: is the cache cleared already each time do_stuff is called?

My suspicion is yes, because I expect that def is executable code, not a compiler macro, and that the decorator will be rebound each time the outer function is run, creating a new cache.

But I'm not sure that I'm right. Can anyone confirm or deny?

9 comments · 100% upvoted · other discussions

comments

PercyJackson235

Question: why are you defining a cached function inside of do_stuff?

patrickbrianmooney [OP]

Specifically so I can cache results just for a single run of the function.

PercyJackson235

Ah, okay. I would say no, because each time you run do_stuff, it creates a new cmp_form, which should have a new cache. But I can check certainty in like half an hour.

patrickbrianmooney [OP]

Checking the cache object in a debugger shows that it is empty on each run. I guess I'm just wondering whether that's something I can rely on, or something that happens to be an artefact of how it happens to be handled in the Python it's running under.

PercyJackson235

You should because the function named cmp_form is a completely separate object during each run of do_stuff. That's is not an implementation detail.

patrickbrianmooney [OP]

Thanks! That's what I thought. I just wanted to make sure I wasn't crazy.