Can functools.cache be used for methods belonging to a class?

I found some conflicting opinions on this topic. Take this very simple example:

import re

class URLSearch:
    def __init__(self, text):
        self.text = text

    def search(self):
        url_pattern = r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+"
        return re.search(url_pattern, self.text)

I did test whether I can decorate search() with @functools.cache or not and it did work. But just because I can, should I?

Yes, it works, but note that a naive usage will keep the objects alive eternally, see Memoizing methods considered harmful - #24 by joyful-giraffe

In all my experiments the return value of the method does not change if the object attributes are changed.

As such you need to be disciplined about not changing your objects after they’re instantiated if you cache.

This also means you should use @cached_property rather than @cache for methods that only take (self). You lose the brackets when you call, which is usually an advantage. And @cached_property is meant for methods, so it might be optimized better.

Then you probably don’t have __eq__ and __hash__ defined, meaning that the cache lookup happens by identity. functools.cache does not try to do anything clever. This is the same behaviour if you were instead using a standalone function with the decorator.

I would be wary of creating a new cache for each instance of a class. If I want that, I’ll control it and implement a simple instance dictionary myself.

Most of the time, if I’m bothering to add code and request resources to implement caching, I want to make as much use of the cache as possible, and let anything else use it that wants to. So I’d prefer to cache class methods and static methods. At which point it’s a small step to cacheing a global function.