It's not clear to me why people prefer an extra function which would be
exactly equivalent to lru_cache in the expected use case (i.e. decorating a
function without arguments). It seems like a good way to cause confusion,
especially for beginners. Based on the Zen, there should be one obvious way
to do it.

On Sun, Apr 26, 2020 at 6:33 PM Tom Forbes <t...@tomforb.es> wrote:

> What if the functions requires arguments? How to cache calls with
> different arguments? What if some arguments are not hashable?
>
> Then I think lru_cache is perfectly suitable for that use case. `once()`
> would only be useful if you’re calling a function with no arguments and
> therefore return a constant value. I originally thought that an exception
> could be raised if `@once()` was used with a function that accepted
> arguments, but it might be better to instead simply ignore arguments
> instead? It could help with some situations where your method accepts a
> single “self” argument, or another value, that you know will be constant
> across calls.
>
> Why ``functools``? Why not your own library or a package at PyPI. Like
> https://pypi.org/project/cachetools/ ?
>
> Because `lru_cache` fits the use case almost perfectly, is available in
> the stdlib and is very, very fast. As such people are using it like they
> would use `once()` which to me feels like a good argument to either special
> case `lru_cache()` to account for this or explicitly add a complimentary
> `once()` method alongside `lru_cache`. Adding a complimentary method seems
> better.
>
> On Sun, Apr 26, 2020 at 4:26 PM Oleg Broytman <p...@phdru.name> wrote:
>
>> On Sun, Apr 26, 2020 at 03:03:16PM +0100, Tom Forbes <t...@tomforb.es>
>> wrote:
>> > Hello,
>> > 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.
>> My rationale for suggesting this addition is twofold:
>> >
>> > First: It???s fairly common to use `lru_cache()` to implement this
>> behaviour. We use this inside Django (example <
>> https://github.com/django/django/blob/77aa74cb70dd85497dbade6bc0f394aa41e88c94/django/forms/renderers.py#L19>),
>> internally in other projects at my workplace, inside the stdlib itself <
>> https://github.com/python/cpython/blob/2fa67df605e4b0803e7e3aac0b85d851b4b4e09a/Lib/ipaddress.py#L1324>
>> and in numerous other projects. In the first few pages of a Github code
>> search <
>> https://github.com/search?l=Python&q=%22functools.lru_cache%22&type=Code>
>> it is fairly easy to find examples, any decorated method with no parameters
>> is using `lru_cache()` like `once()`. 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.
>> >
>> > Second: Implementing this in Python, in my opinion, crosses the line of
>> ???annoying and non-trivial enough to not want to repeatedly do it???.
>> While a naive (untested) implementation might be:
>> >
>> > def 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()
>>
>> What if the functions requires arguments? How to cache calls with
>> different arguments? What if some arguments are not hashable?
>>
>> Why ``functools``? Why not your own library or a package at PyPI. Like
>> https://pypi.org/project/cachetools/ ?
>>
>> >         return obj
>> >     return inner
>> >
>> > While to the people who are likely going to be reading this mailing
>> this the code above is understandable and potentially even somewhat simple.
>> However to a lot of people who might not have had experience with writing
>> decorators or understand sentinel objects and their use the above code
>> might be incomprehensible. A much more common, and in my opinion worse,
>> implementation that I???ve seen is something along the lines of this:
>> >
>> > _value = None
>> > def get_value():
>> >     nonlocal _value
>> >     if _value is None:
>> >         _value = some_function()
>> >     return _value
>> >
>> > Which is not ideal for obvious reasons. And these are not even
>> including a potentially key feature: locking the wrapped function so that
>> it is only called once if it is invoked from multiple threads at once.
>> >
>> > So, I???d like to propose adding a `once()` decorator to functools that:
>> > 1. Has a C implementation, keeping the speed on-par with `lru_cache()`
>> > 2. Ensures that the wrapped function is only called once when invoked
>> by multiple threads
>> >
>> > For some related discussion about this idea and lru_cache, please see
>> my thread on  <
>> https://discuss.python.org/t/reduce-the-overhead-of-functools-lru-cache-for-functions-with-no-parameters/3956
>> >discuss.python.org <http://discuss.python.org/>.
>>
>> Oleg.
>> --
>>     Oleg Broytman            https://phdru.name/
>> p...@phdru.name
>>            Programmers don't die, they just GOSUB without RETURN.
>> _______________________________________________
>> Python-ideas mailing list -- python-ideas@python.org
>> To unsubscribe send an email to python-ideas-le...@python.org
>> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>> Message archived at
>> https://mail.python.org/archives/list/python-ideas@python.org/message/74ZGZRB4JF6EPVB5E7WHL44KZUGEUELV/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/2BDIXRRLGJD3JWNUJCCB227SGCQK2YN5/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/B3SID5EZZRWEYXLWRLA4ITLWKC75XNHO/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to