Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Python Cached Property Stays Stale After a Change: Invalidate the Instance Attribute

A cached property does not recalculate when the fields used to compute it change.

By ON Lab2 min readSources checked November 10, 2026 (KST)

cached_property stores its computed value as a normal instance attribute. Changing another field does not invalidate that value; deleting the cached attribute allows the next access to recompute it.

Check the failure with a small fixture

A cached property does not recalculate when the fields used to compute it change.

from functools import cached_property
class Batch:
    def __init__(self, count):
        self.count = count
        self.calls = 0
    @cached_property
    def doubled(self):
        self.calls += 1
        return self.count * 2
batch = Batch(3)
assert batch.doubled == 6
batch.count = 9
assert batch.doubled == 6 and batch.calls == 1
del batch.doubled
assert batch.doubled == 18 and batch.calls == 2
batch.doubled = 100
assert batch.doubled == 100 and batch.calls == 2

What the result means

The cached value exists in the instance dictionary after its first read. Later reads see that stored value before the descriptor needs to calculate anything. The final assignment demonstrates that a caller can override it; a cached property is not automatically a read-only, dependency-tracked calculation.

Choose the correction for your caller

For immutable objects, a once-per-instance cache may be the intended design. For mutable state, invalidate the property in the same operation that updates its dependencies, or choose an ordinary property when recalculation is cheap. To invalidate conditionally without raising when the cache was never populated, an owned class can remove its cache key through self.__dict__.pop("doubled", None). Keep that dependency relationship inside the class rather than requiring every caller to remember it.

Limits and the next check

cached_property requires Python 3.8 or later and an instance with a mutable __dict__. Do not assume one computation under concurrent access; arrange synchronization if duplicate evaluation is unsafe. This per-instance cache differs from lru_cache and has no cache_clear method on the computed value.

Related: Compare a related data or execution contract.

The embedded Python example was executed as an isolated local script on November 10, 2026 (KST), using Python 3.11.6. It demonstrates the stated boundary; it is not a test of your application or a promise of compatibility with every Python release.

Sources & further reading