On Tuesday, 1 August 2017 15:54:42 UTC+1, t...@tomforb.es  wrote:
> > _sentinel = object()
> > _val = _sentinel
> > def val():
> >     if _val is _sentinel:
> >         # Calculate _val
> >     return _val
> > 
> > seems entirely sufficient for this case. Write a custom decorator if you 
> > use the idiom often enough to make it worth the effort.
> 
> I did some timings with this as part of my timings above and found it to be 
> significantly slower than lru_cache with the C extension. I had to add 
> `nonlocal` to get `_val` to resolve, which I think kills performance a bit.
> 
> I agree with the premise though, it might be worth exploring.

It's worth pointing out that there's nothing *wrong* with using lru_cache with 
maxsize=None. You're going to find it hard to get a pure-Python equivalent 
that's faster (after all, even maintaining a single variable is still a dict 
lookup, which is all the cache does when LRU functionality is disabled).

Certainly if you only ever call with no arguments there's little point in an 
LRU cache, so maxsize=None ("the LRU feature is disabled") is logical.

Whether that approach clearly expresses your intent is maybe a little less 
obvious, but you could always write a custom decorator to make your intent 
clear:

>>> from functools import lru_cache
>>> def only_call_once(fn):
...     return lru_cache(maxsize=None)(fn)
...
>>> @only_call_once
... def f():
...     print("Called!")
...     return 1
...
>>> f()
Called!
1
>>> f()
1

Paul
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to