0Pricing
Python Academy · Lesson

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))  # 3628800

Cache 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      # recomputed

Using 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)   # cached

Quick 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

  1. itertools: Infinite and Finite Iterators
  2. itertools: Combinatorics
  3. functools: partial and reduce
  4. functools: lru_cache and cached_property
← Back to Python Academy