Python etc / functools.lru_cache

Published: 15 December 2020, 18:00

Decorator functools.lru_cache caches the function result based on the given arguments:

from functools import lru_cache
@lru_cache(maxsize=32)
def say(phrase):
  print(phrase)
  return len(phrase)

say('hello')
# hello
# 5

say('pythonetc')
# pythonetc
# 9

# the function is not called, the result is cached
say('hello')
# 5

The only limitation is that all arguments must be hashable:

say({})
# TypeError: unhashable type: 'dict'

The decorator is useful for recursive algorithms and costly operations:

@lru_cache(maxsize=32)
def fib(n):
  if n <= 2:
    return 1
  return fib(n-1) + fib(n-2)

fib(30)
# 832040

Also, the decorator provides a few helpful methods:

fib.cache_info()
# CacheInfo(hits=27, misses=30, maxsize=32, currsize=30)

fib.cache_clear()
fib.cache_info()
# CacheInfo(hits=0, misses=0, maxsize=32, currsize=0)

# Introduced in Python 3.9:
fib.cache_parameters()
# {'maxsize': None, 'typed': False}

And the last thing for today, you’ll be surprised how fast lru_cache is:

def nop():
    return None

@lru_cache(maxsize=1)
def nop_cached():
    return None

%timeit nop()
# 49 ns ± 0.348 ns per loop

# cached faster!
%timeit nop_cached()
# 39.3 ns ± 0.118 ns per loop