gh-102618: Introduce a functools.cached_method decorator#150002
Conversation
Documentation build overview
|
resolves python#102618 This definition of `cached_method` is based on the discussion on DPO: https://discuss.python.org/t/107164 Some tradeoffs need to be made in any version of such a decorator. In this particular implementation, the choices made are as follows: - lru_cache will be used under the hood, and `cache_clear()` and `cache_info()` will be exposed - caches will be stored in a separate dict, indexed by `id(self)` -- meaning instances do not need to be hashable and will not share caches - weakrefs will be used to delete entries from the cache, so the instances must be weak-referencable - lru_cache itself is not threadsafe, but initialization of the caches is threadsafe -- this avoids confusing scenarios in which cache entries "disappear" New documentation is included, marked for 3.16, and a small number of new tests are added.
| return self | ||
|
|
||
| def __get__(self, instance, owner=None): | ||
| # similar to singledispatch(), we want to defer use of weakref until/unless it |
There was a problem hiding this comment.
nit: imperative voice is cleaner
| # similar to singledispatch(), we want to defer use of weakref until/unless it | |
| # similar to singledispatch(), defer use of weakref until/unless it |
| update_wrapper(self, func) | ||
| return self | ||
|
|
||
| def __get__(self, instance, owner=None): |
There was a problem hiding this comment.
Thanks for proposing this, @sirosen, and especially for the call out on the jaraco.functools implementation. One of the caveats of that implementation is that you can't further wrap the resulting object (e.g. @property\n@cached_method). Does this approach satisfy that use case or does it have the same limitation? If it has the limitation, it should be called out in the docs (or at least the doc string), and maybe should have a test capturing the known limitation. If it doesn't have the limitation, does that mean that cached_property could potentially be superseded by a composition of property and cached_method?
There was a problem hiding this comment.
This still has the problem, although maybe it can be solved (?). I'll poke at the possibilities but will probably make a doc update shortly.
Right now, if you try to stack this with @property, it will emit a TypeError when called because the same cached_method instance gets assigned multiple times.
resolves #102618
This definition of
cached_methodis based on the discussion on DPO:https://discuss.python.org/t/107164
Some tradeoffs need to be made in any version of such a decorator. In
this particular implementation, the choices made are as follows:
lru_cache will be used under the hood, and
cache_clear()andcache_info()will be exposedcaches will be stored in a separate dict, indexed by
id(self)--meaning instances do not need to be hashable and will not share caches
weakrefs will be used to delete entries from the cache, so the
instances must be weak-referencable
lru_cache itself is not threadsafe, but initialization of the caches
is threadsafe -- this avoids confusing scenarios in which cache entries
"disappear"
New documentation is included, marked for 3.16, and a small number of new
tests are added.
In addition to @rhettinger's review, as the listed owner for functools, @sobolevn expressed interest in reviewing changes.
@kenahoo and @stevendaprano also want a look based on their prior interest.
Everyone I've spoken with about this change1 has been supportive of the core idea. In particular @jaraco noted that he would support this addition, and maintains a very different implementation. There are many other ways of writing this, with different tradeoffs. Perhaps the most notable class of those are versions which store caches on the instance itself, like this one suggested here in the DPO discussion -- this writes the cached method into
__dict__, similarly tocached_property.Of course, I'm happy to alter or re-approach any part of this per review! 😄
Footnotes
at PyCon US 2026 ↩