Since the function has no parameters and is pre-computed, why force all users to *call* it? The @once decorator could just return the value of calling the function:
def once(func): return func() @once def pwd(): return os.getcwd() print(pwd) On Sun, Apr 26, 2020 at 7:09 AM 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() > 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. > _______________________________________________ > 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/5OR3LJO7LOL6SC4OOGKFIVNNH4KADBPG/ > Code of Conduct: http://python.org/psf/codeofconduct/ > -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________ 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/MNZS6XLDUHASJJOHQ3OQZVYWRLTNJJ2W/ Code of Conduct: http://python.org/psf/codeofconduct/