On Thursday, 3 August 2017 16:37:22 UTC+1, Ian wrote: > On Thu, Aug 3, 2017 at 8:35 AM, Paul Moore ...@gmail.com> wrote: > > 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). > > The single variable is only a dict lookup if it's a global. Locals and > closures are faster. > > def simple_cache(function): > sentinel = object() > cached = sentinel > > @functools.wraps(function) > def wrapper(*args, **kwargs): > nonlocal cached > if args or kwargs: > return function(*args, **kwargs) # No caching with args > if cached is sentinel: > cached = function() > return cached > return wrapper > > *Zero* dict lookups at call-time. If that's not (marginally) faster > than lru_cache with maxsize=None I'll eat my socks.
I hope you washed them! def test_func(): return 1 %timeit test_simple_cache() The slowest run took 11.06 times longer than the fastest. This could mean that an intermediate result is being cached. 10000000 loops, best of 3: 183 ns per loop %timeit test_lru_cache() The slowest run took 42.92 times longer than the fastest. This could mean that an intermediate result is being cached. 10000000 loops, best of 3: 46.9 ns per loop %timeit test_func() 10000000 loops, best of 3: 55.3 ns per loop -- https://mail.python.org/mailman/listinfo/python-list