Finding a path forward for `functools.cached_property`

Flask’s locked cached property technically has this issue, but it’s mitigated somewhat by the fact that there’s typically only one app instance, not many. Additionally, WSGI workers are commonly separate processes, where a lock doesn’t affect other requests. That said, I’ve thought before about removing it, and I should go look again because it’s probably unnecessary.

The reason Werkzeug implements its own (non-locked) cached property is because functools.cached_property didn’t exist. It also has some features that functools does not:

  • __set__ to update the value directly
  • __del__ to reset the cache so it’s computed again
  • Doesn’t require __dict__, classes that use __slots__ can add a special _cache_{name} slot for each property.
  • Is a subclass of property, and also generically typed, so it plays nice with typing.

The functools version has that functionality, by virtue of being a non-data descriptor (that is, not implementing __set__ itself).
It’s not obvious, though. Perhaps it should be advertised in the docs? Edit: Oh, it is. Never mind. And the __slots__ use case is covered too.

Is there a specific benefit from that? The standard library’s implementation can also be set (even before the caching has occurred), but because no __set__ is defined, the descriptor will simply be replaced.

That’s arguable. Yes, you can use it with slots but it requires you to put __dict__ in the __slots__ which defeats the memory savings that to my knowledge are main use case for slotted classes. Meanwhile, werkzeug implementation solves it by allowing you to define a slot for the cached value, which means you don’t have to have an instance dict.

2 Likes

It could just be that I didn’t realize __set__ and __delete__ weren’t required. Or maybe it didn’t work well with the __slots__ support. It’s been a while since I worked on that code, I don’t remember anymore.

If functools were to drop the lock, which I agree is a good idea, I would look at using it again.

Actually, __slots__ also offers a speed benefit, even if there’s also a __dict__. Esp. in 3.11 and later. (For properties this benefit is overwhelmed by the cost of calling it.)

1 Like