On 4/30/20 4:47 PM, raymond.hettinger@gmail.com wrote:
Would either of the existing solutions work for you?

class X:
    def __init__(self, name):
        self.name = name

    @cached_property
    def title(self):
      print("compute title once")
      return self.name.title()

    @property
    @lru_cache
    def upper(self):
      print("compute uppper once")
      return self.name.upper()

The second one seems a bit dangerous in that it will erroneously keep objects alive until they are either ejected from the cache or until the class itself is collected (plus only 128 objects would be in the cache at one time): https://bugs.python.org/issue19859

Thanks for the concrete example.  AFAICT, it doesn't require (and probably shouldn't have) a lock to be held for the duration of the call.  Would it be fair to say the 100% of your needs would be met if we just added this to the functools module?

      call_once = lru_cache(maxsize=None)
I am -0 on adding `call_once = lru_cache(maxsize=None)` here. I feel like it could be misleading in that people might think that it ensures that the function is called exactly once (it reminds me of the FnOnce trait in Rust), and all it buys us is a nice way to advertise "here's a use case for lru_cache".

That said, in any of the times I've had one of these "call exactly one time" situations, the biggest constraint I've had is that I always wanted the return value to be the same object so that `f(x) is f(x)`, but I've never had a situation where it was required that the function be called exactly once, so I rarely if ever have bothered to get that property.

I suppose I could imagine a situation where calling the function mutates or consumes an object as part of the call, like:

class LazyList:
    def __init__(self, some_iterator):
        self._iter = some_iterator
        self._list = None

    @call_once
    def as_list(self):
        self._list = list(self._iter)
        return self._list

But I think it's just speculation to imagine anyone needs that or would find it useful, so I'm in favor of waiting for someone to chime in with a concrete use case where this property would be valuable.

Best,
Paul