lru-method-cache
A drop-in replacement for functools.lru_cache designed for methods.
The problem
Using functools.lru_cache on methods causes memory leaks. The cache is
stored on the class (via the decorator), and every cached call stores a
strong reference to self as part of the cache key. This prevents
instances from being garbage collected, even after all other references
are gone:
from functools import lru_cache
class MyClass:
@lru_cache(maxsize=128)
def expensive(self, x):
return x * 2
a = MyClass()
a.expensive(1)
del a # instance is NOT garbage collected — the cache still holds a reference
This is a well-known issue with no satisfying solution in the standard library. Here are some references to learn more.
- Python Docs: https://docs.python.org/3/faq/programming.html#how-do-i-cache-method-calls
- Blog post: https://rednafi.com/python/lru_cache_on_methods/
- Stack Overflow: https://stackoverflow.com/q/33672412
The solution
lru-method-cache provides lru_method_cache, which stores the cache
per instance using a descriptor. When an instance is garbage
collected, its cache is automatically cleaned up via weakref.finalize.
from lru_method_cache import lru_method_cache
class MyClass:
@lru_method_cache(maxsize=128)
def expensive(self, x):
return x * 2
a = MyClass()
a.expensive(1)
del a # instance is garbage collected, the respective cache is freed
Signature normalization
Unlike functools.lru_cache, lru_method_cache normalizes call
signatures so that positional and keyword forms of the same argument
produce the same cache key:
class MyClass:
@lru_method_cache
def compute(self, a, b, c=0):
return a + b + c
obj = MyClass()
obj.compute(1, 2) # miss
obj.compute(1, b=2) # hit — same as above
obj.compute(a=1, b=2) # hit — same as above
functools.lru_cache treats these as three separate cache entries.
Usage
from lru_method_cache import lru_method_cache
class MyClass:
# Without parentheses (defaults: max_size=128, typed=False)
@lru_method_cache
def method_a(self, x):
...
# With parentheses
@lru_method_cache(max_size=256, typed=True)
def method_b(self, x):
...
# Unlimited cache
@lru_method_cache(max_size=None)
def method_c(self, x):
...
The familiar cache_info() and cache_clear() methods are available on
each bound method, just like functools.lru_cache:
obj = MyClass()
obj.method_a(1)
obj.method_a(2)
obj.method_a(1) # cache hit
obj.method_a.cache_info()
# CacheInfo(hits=1, misses=2, max_size=128, cur_size=2)
obj.method_a.cache_clear()
Parameters
| Parameter | Default | Description |
|---|---|---|
max_size |
128 |
Maximum number of cached results. None for unlimited. |
typed |
False |
If True, arguments of different types are cached separately (e.g., 1 and 1.0 are distinct). |
Classmethods and staticmethods
lru_method_cache is only for instance methods. Applying it to a
classmethod or staticmethod raises TypeError with a helpful
message — those don't have the memory leak problem, so
functools.lru_cache works fine for them.
Classes with __slots__
If a class uses __slots__ without __weakref__, the cache still works
but a UserWarning is issued because cleanup cannot happen automatically
when the instance is deleted. Add "__weakref__" to __slots__ to
enable automatic cleanup.
How it compares
There are certain other clever solutions for the issue of using lru_cache on class methods. Here is a comparison of this project to some of other solutions:
| Approach | Memory-safe | Signature normalization | Per-instance cache | Thread-safe |
|---|---|---|---|---|
functools.lru_cache |
No | No | No | Yes |
methodtools.lru_cache |
Yes | No | Yes | Yes |
cachetools + manual wiring |
Yes | No | Manual | Manual |
lru-method-cache.lru_method_cache |
Yes | Yes | Yes | Yes |
Design philosophy
lru-method-cache uses only Python's standard library — no third-party
dependencies. The implementation is a single, short module that is easy
to read, inspect, and audit. If you want to understand exactly what your
caching decorator does, you can review the entire source in a few
moments.
Installation
pip install lru-method-cache
Requirements
Python 3.10+. No third-party dependencies.
License
MIT
Metadata
Release files for lru-method-cache 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lru_method_cache-0.2.0.tar.gz | 9.2 kB | With provenance | Details for lru_method_cache-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lru_method_cache-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for lru_method_cache-0.2.0-py3-none-any.whl |
Total release size: 16.4 kB
Release files / lru_method_cache-0.2.0.tar.gz
| Download URL | lru_method_cache-0.2.0.tar.gz |
|---|---|
| Size | 9.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e777a8d2dc363b121ce8c5e34dee063a28f37eabe56c35e6dd9b3a52b41000cc
|
|
BLAKE2b-256 checksum How to use checksums |
3679ca29614d46469cde804e723769e2c96f682a1ce5d3a5a625038bf7192f05
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 10, 2026.
Transparency logRelease files / lru_method_cache-0.2.0-py3-none-any.whl
| Download URL | lru_method_cache-0.2.0-py3-none-any.whl |
|---|---|
| Size | 7.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
87f23d96ae1f00d3fe2dda399565d7e7e94fc29d253cb3d356574d3ada5d7ca8
|
|
BLAKE2b-256 checksum How to use checksums |
a58529a4de6faeebba1d491d874d3fdb6f8d80255b9f8436c5533e643b3dac52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 10, 2026.
Transparency logSecurity for lru-method-cache 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for lru_method_cache-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 10, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.