This rule raises an issue when an instance method is decorated with functools.lru_cache or functools.cache.
functools.lru_cache and functools.cache store call results in a process-wide cache keyed by the function arguments. On an
instance method, self is part of that key.
The cache therefore keeps a strong reference to every instance that was used as a receiver. Those instances and anything they reference cannot be
garbage-collected for as long as the cache entry lives. The instances lifetimes are coupled to a global memoization table. With an unbounded
@cache, or a large @lru_cache(maxsize=…), memory use grows with the number of distinct instances.
Caching couples the lifetime of business objects to a global memoization table.
Do not raise on @staticmethod or @classmethod methods: there is no per-instance self retained by the
cache.
Do not raise on methods of enum.Enum subclasses: enum members are singletons, so retaining them is intentional and bounded.
Move the cache to a free function that takes only the values needed for the computation, then call that function from the method. Alternatively,
cache on a pure helper that does not close over self, or use an instance-local memo if the lifetime must match the object.
from functools import lru_cache
class Number:
def __init__(self, value: int) -> None:
self.value = value
@lru_cache # Noncompliant: cache retains "self"
def squared(self) -> int:
return self.value * self.value
from functools import lru_cache
@lru_cache
def square(value: int) -> int:
return value * value
class Number:
def __init__(self, value: int) -> None:
self.value = value
def squared(self) -> int:
return square(self.value)
functools.lru_cachefunctools.cache