functools: lru_cache and cached_property
Cache expensive computations with lru_cache and cached_property.
functools: lru_cache and cached_property is a free Python Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is Memoization?
Memoization caches the result of a function call keyed by its arguments. Repeated calls with the same arguments return the cached result instantly.
def slow_fib(n):
if n < 2: return n
return slow_fib(n-1) + slow_fib(n-2)
# slow_fib(35) makes ~29 million calls
# With caching it makes only 35@lru_cache
@functools.lru_cache(maxsize=128) caches up to maxsize recent results. Set maxsize=None for an unbounded cache.
import functools
@functools.lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
print(fib(50)) # instant@cache — Python 3.9+
functools.cache is shorthand for lru_cache(maxsize=None) — an unbounded cache with a cleaner name.
import functools
@functools.cache
def factorial(n):
return n * factorial(n-1) if n else 1
print(factorial(10)) # 3628800Cache Info and Clear
Cached functions expose .cache_info() (hits, misses, size) and .cache_clear().
import functools
@functools.lru_cache(maxsize=100)
def square(n):
return n * n
for i in range(5): square(i % 3)
print(square.cache_info())
# CacheInfo(hits=2, misses=3, maxsize=100, currsize=3)
square.cache_clear()LRU Eviction Policy
LRU (Least Recently Used) evicts the item that was accessed least recently when the cache is full.
import functools
@functools.lru_cache(maxsize=3)
def compute(n):
print(f"computing {n}")
return n**2
for x in [1,2,3,4,1]: # 4 evicts 1 (LRU), then 1 re-computes
compute(x)Hashable Arguments Only
lru_cache requires all arguments to be hashable. Lists and dicts are not hashable; use tuples instead.
import functools
@functools.lru_cache(maxsize=None)
def sum_tuple(t): # tuple is hashable
return sum(t)
print(sum_tuple((1,2,3))) # 6
# sum_tuple([1,2,3]) # TypeError@cached_property
functools.cached_property computes a property once and caches the result on the instance, replacing the descriptor with the value.
import functools
class Circle:
def __init__(self, r):
self.r = r
@functools.cached_property
def area(self):
import math
print("computing...")
return math.pi * self.r ** 2
c = Circle(5)
print(c.area) # computing... 78.53...
print(c.area) # 78.53... (cached, no print)cached_property vs property
@property recomputes on every access. @cached_property computes once and stores the result in instance.__dict__.
import functools
class Expensive:
@property
def always(self): # runs every access
return sum(range(1_000_000))
@functools.cached_property
def once(self): # runs only first access
return sum(range(1_000_000))Thread Safety of cached_property
cached_property is not thread-safe. If multiple threads access it simultaneously, the computation may run more than once. Use a lock if needed.
import functools, threading
class SafeCache:
_lock = threading.Lock()
@functools.cached_property
def data(self):
with self._lock:
return expensive_computation()Invalidating cached_property
Delete the instance attribute to invalidate the cache and force recomputation on the next access.
import functools
class Report:
@functools.cached_property
def summary(self):
return compute_summary()
r = Report()
_ = r.summary # computed
del r.summary # invalidate
_ = r.summary # recomputedUsing lru_cache as API Cache
Cache API responses for a session to avoid redundant network calls. Clear the cache when fresh data is needed.
import functools, urllib.request, json
@functools.lru_cache(maxsize=32)
def get_user(user_id):
url = f"https://api.example.com/users/{user_id}"
with urllib.request.urlopen(url) as r:
return json.loads(r.read())
user = get_user(42) # network call
user = get_user(42) # cachedQuick Check
What method clears all cached results of an @lru_cache decorated function?
Recap
@lru_cache caches function results keyed by arguments (must be hashable). @cache is an unbounded alias. @cached_property caches a property computation per instance. Inspect with cache_info() and reset with cache_clear().
Frequently asked questions
Is the “functools: lru_cache and cached_property” lesson free?
Yes — the full text of “functools: lru_cache and cached_property” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.
What will I learn in “functools: lru_cache and cached_property”?
Cache expensive computations with lru_cache and cached_property. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Python Academy?
No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “functools: lru_cache and cached_property” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Python Academy lesson?
Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- itertools: Infinite and Finite Iterators
- itertools: Combinatorics
- functools: partial and reduce
- functools: lru_cache and cached_property