> t...@tomforb.es wrote: > > I would like to suggest adding a simple “once” method to functools. As the > name suggests, this would be a decorator that would call the decorated > function, cache the result and return it with subsequent calls.
It seems like you would get just about everything you want with one line: call_once = lru_cache(maxsize=None) which would be used like this: @call_once def welcome(): len('hello') > Using lru_cache like this works but it’s not as efficient as it could be - in > every case you’re adding lru_cache overhead despite not requiring it. You're likely imagining more overhead than there actually is. Used as shown above, the lru_cache() is astonishingly small and efficient. Access time is slightly cheaper than writing d[()] where d={(): some_constant}. The infinite_lru_cache_wrapper() just makes a single dict lookup and returns the value.¹ The lru_cache_make_key() function just increments the empty args tuple and returns it.² And because it is a C object, calling it will be faster than for a Python function that just returns a constant, "lambda: some_constant()". This is very, very fast. Raymond ¹ https://github.com/python/cpython/blob/master/Modules/_functoolsmodule.c#L870 ² https://github.com/python/cpython/blob/master/Modules/_functoolsmodule.c#L809 > > Hello, > After a great discussion in python-ideas[1][2] it was suggested that I > cross-post this proposal to python-dev to gather more comments from those who > don't follow python-ideas. > > The proposal is to add a "call_once" decorator to the functools module that, > as the name suggests, calls a wrapped function once, caching the result and > returning it with subsequent invocations. The rationale behind this proposal > is that: > 1. Developers are using "lru_cache" to achieve this right now, which is less > efficient than it could be > 2. Special casing "lru_cache" to account for zero arity methods isn't trivial > and we shouldn't endorse lru_cache as a way of achieving "call_once" > semantics > 3. Implementing a thread-safe (or even non-thread safe) "call_once" method is > non-trivial > 4. It complements the lru_cache and cached_property methods currently present > in functools. > > The specifics of the method would be: > 1. The wrapped method is guaranteed to only be called once when called for > the first time by concurrent threads > 2. Only functions with no arguments can be wrapped, otherwise an exception is > thrown > 3. There is a C implementation to keep speed parity with lru_cache > > I've included a naive implementation below (that doesn't meet any of the > specifics listed above) to illustrate the general idea of the proposal: > > ``` > def call_once(func): > sentinel = object() # in case the wrapped method returns None > obj = sentinel > @functools.wraps(func) > def inner(): > nonlocal obj, sentinel > if obj is sentinel: > obj = func() > return obj > return inner > ``` > > I'd welcome any feedback on this proposal, and if the response is favourable > I'd love to attempt to implement it. > > 1. > https://mail.python.org/archives/list/python-id...@python.org/thread/5OR3LJO7LOL6SC4OOGKFIVNNH4KADBPG/#5OR3LJO7LOL6SC4OOGKFIVNNH4KADBPG > 2. > https://discuss.python.org/t/reduce-the-overhead-of-functools-lru-cache-for-functions-with-no-parameters/3956 > _______________________________________________ > Python-Dev mailing list -- python-dev@python.org > To unsubscribe send an email to python-dev-le...@python.org > https://mail.python.org/mailman3/lists/python-dev.python.org/ > Message archived at > https://mail.python.org/archives/list/python-dev@python.org/message/5CFUCM4W3Z36U3GZ6Q3XBLDEVZLNFS63/ > Code of Conduct: http://python.org/psf/codeofconduct/ _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/OYBYJ2373OTHALHTPQJV5EBX6N5M4DDL/ Code of Conduct: http://python.org/psf/codeofconduct/