Python Academy · Lesson

functools: lru_cache and cached_property

Cache expensive computations with lru_cache and cached_property.

Lesson 4 of 413 steps

functools: lru_cache and cached_property is a free Python Academy lesson on CoddyKit. This is 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, and your progress syncs across the web and the CoddyKit app. The Python Academy course includes 4 lessons in total.

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().

Free to start

Learn Python with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
76
Lessons
320

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. 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. The Python Academy course includes 4 lessons in total.

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, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

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