Skip to main content

Per-instance LRU caching for methods — a drop-in replacement for functools.lru_cache that avoids memory leaks.

Project description

lru-method-cache

CI codecov PyPI Python

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.

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lru_method_cache-0.2.0.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lru_method_cache-0.2.0-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

File details

Details for the file lru_method_cache-0.2.0.tar.gz.

File metadata

  • Download URL: lru_method_cache-0.2.0.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lru_method_cache-0.2.0.tar.gz
Algorithm Hash digest
SHA256 e777a8d2dc363b121ce8c5e34dee063a28f37eabe56c35e6dd9b3a52b41000cc
MD5 e790377e4b573d535a4dbbc530b4c39c
BLAKE2b-256 3679ca29614d46469cde804e723769e2c96f682a1ce5d3a5a625038bf7192f05

See more details on using hashes here.

Provenance

The following attestation bundles were made for lru_method_cache-0.2.0.tar.gz:

Publisher: publish.yml on mkoistinen/lru-method-cache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lru_method_cache-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for lru_method_cache-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 87f23d96ae1f00d3fe2dda399565d7e7e94fc29d253cb3d356574d3ada5d7ca8
MD5 b29f2055771fc20d25908cb18eda2c44
BLAKE2b-256 a58529a4de6faeebba1d491d874d3fdb6f8d80255b9f8436c5533e643b3dac52

See more details on using hashes here.

Provenance

The following attestation bundles were made for lru_method_cache-0.2.0-py3-none-any.whl:

Publisher: publish.yml on mkoistinen/lru-method-cache

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page