Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python cached_property: delete the instance value when source state changes

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

cached_property computes an attribute on first access and stores the result in the instance dictionary.

Download Python source kit

Operation contract

The invoice stores an immutable tuple of minor-unit amounts and counts summary evaluations. Two reads use one computed total. Replacing the tuple without deleting the cached attribute would leave a stale total; the setter therefore deletes the cached value after validating the new amounts. A later read recomputes it. The cache is per instance, not a global memo table.

Failure and ownership boundary

This descriptor needs a mutable instance __dict__. It is unsuitable for a slots-only instance without one, and concurrent first reads may run the getter more than once. Invalidation belongs with every mutation path. Python properties: validate mutation at the public attribute boundary, Python lru_cache: bound retention and include the revision in the key and Python dataclasses: frozen fields require an immutable value model show alternatives.

Working program

python
from functools import cached_property

class Invoice:
    def __init__(self, amounts):
        self.computations = 0
        self.replace(amounts)
    def replace(self, amounts):
        candidate = tuple(amounts)
        if len(candidate) > 20 or any(type(amount) is not int or not 0 <= amount <= 1000 for amount in candidate):
            raise ValueError("bounded minor units")
        self.amounts = candidate
        self.__dict__.pop("total", None)
    @cached_property
    def total(self):
        self.computations += 1
        return sum(self.amounts)

invoice = Invoice([125, 75])
print(invoice.total, invoice.total, invoice.computations)
invoice.replace([125, 100])
print(invoice.total, invoice.computations)

Output

Output
200 200 1
225 2

Costs and limits

An uncached total scans n amounts; a later cached read is an attribute lookup. The cached integer and instance dictionary entry remain until deletion or collection. This program has no concurrent callers, so it does not establish one-computation semantics under a race.

Common Mistakes

  • Changing source state without invalidation leaves a stale cached value.
  • cached_property requires an instance dictionary and does not serialize concurrent first access.

Connected lessons

Python properties: validate mutation at the public attribute boundary, Python lru_cache: bound retention and include the revision in the key, Python dataclasses: frozen fields require an immutable value model.

python
cached-property-invalidation
Storage details