Skip to content

cached_property no longer works as a data descriptor in Python 3.12 #106292

Closed
@treyhunner

Description

@treyhunner

Bug report

In Python 3.11 and below, when cached_property was inherited from, the __get__ method would always check for the attribute in the cache.
In Python 3.12.0b3 (since #101890 it seems) the __get__ method no longer checks the cache.

This isn't an issue for typical use, but it might be an issue for subclasses.
For example here's a version of cached_property that inherits from the functools version but also allows for a setter (just as @property does).

Since this child class adds a __set__ method, the __get__ method in functools.cached_property will be called before the __dict__ attribute is accessed.

"""Demonstration of cached_property difference in Python 3.12.0b3.""" import functools class settable_cached_property(functools.cached_property): def __init__(self, func): super().__init__(func) self._setter = self._deleter = None def setter(self, setter): self._setter = setter return self def __set__(self, obj, value): if self._setter: self._setter(obj, value) obj.__dict__.pop(self.attrname, None) else: obj.__dict__[self.attrname] = value class Thing: @settable_cached_property def x(self): return self.y thing = Thing() thing.y = 4 print(f"{thing.x = } (should be 4)") thing.y = 5 print(f"{thing.x = } (should still be 4)")

This new behavior may be intended, but I wanted to make a note of it because it does break a previous (undocumented I believe?) assumption that cached_property could be inherited from and turned into a data descriptor.

Your environment

Python 3.12.0b3 on Ubuntu Linux

Linked PRs

Metadata

Metadata

Assignees

Labels

3.12only security fixes3.13bugs and security fixesstdlibPython modules in the Lib dirtype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions