I agree, that was the topic of my original post to the python-ideas discussion 
group[1]. I thought we should special-case `lru_cache()` to account for this 
use case.

The general consensus was that a `once()` decorator would be less confusing and 
more semantically correct than using `lru_cache` like this. I can also see the 
reasoning behind that point of view, and it could be further argued that using 
`lru_cache()` in a non-lru way might be more confusing.

Perhaps we could alter the documentation to explicitly “bless” this approach, 
but as shown in the original python-ideas discussion people had strong negative 
opinions towards that approach.

1. 
https://discuss.python.org/t/reduce-the-overhead-of-functools-lru-cache-for-functions-with-no-parameters/3956

> On 26 Apr 2020, at 17:43, Alex Hall <alex.moj...@gmail.com> wrote:
> 
> 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 
> <mailto: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/ <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 
> <mailto:p...@phdru.name>> wrote:
> On Sun, Apr 26, 2020 at 03:03:16PM +0100, Tom Forbes <t...@tomforb.es 
> <mailto: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
> >  
> > <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
> >  
> > <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 
> > <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/ <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
> >  
> > <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/> <http://discuss.python.org/ 
> > <http://discuss.python.org/>>.
> 
> Oleg.
> --
>     Oleg Broytman            https://phdru.name/ <https://phdru.name/>        
>     p...@phdru.name <mailto:p...@phdru.name>
>            Programmers don't die, they just GOSUB without RETURN.
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org 
> <mailto:python-ideas@python.org>
> To unsubscribe send an email to python-ideas-le...@python.org 
> <mailto:python-ideas-le...@python.org>
> https://mail.python.org/mailman3/lists/python-ideas.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/
>  
> <https://mail.python.org/archives/list/python-ideas@python.org/message/74ZGZRB4JF6EPVB5E7WHL44KZUGEUELV/>
> Code of Conduct: http://python.org/psf/codeofconduct/ 
> <http://python.org/psf/codeofconduct/>
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org 
> <mailto:python-ideas@python.org>
> To unsubscribe send an email to python-ideas-le...@python.org 
> <mailto:python-ideas-le...@python.org>
> https://mail.python.org/mailman3/lists/python-ideas.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/
>  
> <https://mail.python.org/archives/list/python-ideas@python.org/message/2BDIXRRLGJD3JWNUJCCB227SGCQK2YN5/>
> Code of Conduct: http://python.org/psf/codeofconduct/ 
> <http://python.org/psf/codeofconduct/>

Attachment: signature.asc
Description: Message signed with OpenPGP

_______________________________________________
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/ANL3U3NMF7YYA77HAB224ARDYQPNCEO2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to