0

I can cache an instance attribute like so:

from dataclasses import dataclass
from functools import cached_property

@dataclass
class Point:
    _x: float

    @cached_property
    def x(self):
        return self._x * 2

>> p = Point(3)
>> p.x
6

I want to have the calculation applied to x every time I call it, using a cached result for subsequent calls to avoid unnecessary computations.

But I also want to change x. While p.x += 1 works with the code above, many places say that @cached_property is meant for immutable values. And in my actual, more complex code, it gives me strange, inscrutable results. I chalked this up to surprising behaviour when the decorator is used with mutable attributes (even though I don't fully understand what's happening).

What's the proper way to cache an instance attribute that changes throughout its lifetime?

5
  • That decorator caches for the lifetime of the instance. If you want to have changes reflected it is not the right choice. Commented Aug 7, 2024 at 6:03
  • p.x += 1 already works to produce p.x equaling 7 with your current code (demo). Please clarify what you actually want. Commented Aug 7, 2024 at 6:05
  • @KlausD. The cached value can be cleared by deleting the instance attribute though according to the doc so depending on what the OP actually wants the cached value can be cleared with the right hook. Commented Aug 7, 2024 at 6:07
  • @blhsing Well that's like saying you can reset the odometer of a car by buying a new car. Commented Aug 7, 2024 at 6:10
  • @KlausD. I believe what the OP really wants is a way to update the _x attribute while making the cached property x recalculated the next time it is read, in which case I don't think your analogy is a fitting one. Commented Aug 7, 2024 at 6:18

1 Answer 1

0

@cached_property is mainly intended for properties that should be considered immutable. The documentation specifically says:

Useful for expensive computed properties of instances that are otherwise effectively immutable.

However, it also mentions that you can clear the cache by deleting the attribute. So you can do:

del p.x
p._x = 5
print(p.x) # this will print 10
Sign up to request clarification or add additional context in comments.

2 Comments

Deleting the attribute in every place where I modify it seems like a bad solution, and @cached_property is not meant to be used like this.
Maybe you can write an @x.setter method that does this, I haven't tried it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.