Python functools lru_cache with class methods: release object
This is not the cleanest solution, but it's entirely transparent to the programmer:
import functools
import weakref
def memoized_method(*lru_args, **lru_kwargs):
def decorator(func):
@functools.wraps(func)
def wrapped_func(self, *args, **kwargs):
# We're storing the wrapped method inside the instance. If we had
# a strong reference to self the instance would never die.
self_weak = weakref.ref(self)
@functools.wraps(func)
@functools.lru_cache(*lru_args, **lru_kwargs)
def cached_method(*args, **kwargs):
return func(self_weak(), *args, **kwargs)
setattr(self, func.__name__, cached_method)
return cached_method(*args, **kwargs)
return wrapped_func
return decorator
It takes the exact same parameters as lru_cache
, and works exactly the same. However it never passes self
to lru_cache
and instead uses a per-instance lru_cache
.
I will introduce methodtools
for this use case.
pip install methodtools
to install https://pypi.org/project/methodtools/
Then your code will work just by replacing functools to methodtools.
from methodtools import lru_cache
class Foo:
@lru_cache(maxsize=16)
def cached_method(self, x):
return x + 5
Of course the gc test also returns 0 too.