0Pricing
Python Academy · Lezione

functools: lru_cache e cached_property

Memorizzi nella cache i calcoli costosi con lru_cache e cached_property.

functools: lru_cache e cached_property è una lezione Python Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Python Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Python Academy include 4 lezioni in totale.

Che cos'è la memoizzazione?

La memoizzazione memorizza nella cache il risultato di una chiamata di funzione, indicizzato in base ai suoi argomenti. Le chiamate ripetute con gli stessi argomenti restituiscono immediatamente il risultato memorizzato.

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) memorizza nella cache fino a maxsize risultati recenti. Imposti maxsize=None per una cache senza limite.

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 è una forma abbreviata di lru_cache(maxsize=None): una cache senza limite con un nome più semplice.

import functools

@functools.cache
def factorial(n):
    return n * factorial(n-1) if n else 1

print(factorial(10))  # 3628800

Informazioni e svuotamento della cache

Le funzioni con cache espongono .cache_info() (hit, miss e dimensione) e .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()

Criterio di espulsione LRU

LRU (Least Recently Used, usato meno di recente) espelle l'elemento a cui si è avuto accesso meno recentemente quando la cache è piena.

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)

Solo argomenti hashable

lru_cache richiede che tutti gli argomenti siano hashable. Le liste e i dizionari non lo sono; utilizzi invece le tuple.

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 calcola una proprietà una volta e memorizza il risultato sull'istanza, sostituendo il descrittore con il valore.

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 o property

@property ricalcola il valore a ogni accesso. @cached_property lo calcola una volta e memorizza il risultato 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))

Sicurezza dei thread con cached_property

cached_property non è thread-safe. Se più thread vi accedono contemporaneamente, il calcolo può essere eseguito più di una volta. Utilizzi un lock se necessario.

import functools, threading

class SafeCache:
    _lock = threading.Lock()

    @functools.cached_property
    def data(self):
        with self._lock:
            return expensive_computation()

Invalidare cached_property

Elimini l'attributo dell'istanza per invalidare la cache e forzare il ricalcolo al successivo accesso.

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

Usare lru_cache come cache API

Memorizzi nella cache le risposte API per tutta la durata di una sessione, così da evitare chiamate di rete ridondanti. Svuoti la cache quando servono dati aggiornati.

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

Verifica rapida

Quale metodo cancella tutti i risultati memorizzati nella cache di una funzione decorata con @lru_cache?

Riepilogo

@lru_cache memorizza nella cache i risultati delle funzioni indicizzati in base agli argomenti, che devono essere hashable. @cache è un alias senza limite. @cached_property memorizza nella cache il calcolo di una proprietà per ogni istanza. Esamini la cache con cache_info() e la reimposti con cache_clear().

Domande Frequenti

La lezione «functools: lru_cache e cached_property» è gratuita?

Sì — il testo completo di «functools: lru_cache e cached_property» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Python Academy, passa a CoddyKit PRO. Il corso Python Academy include 4 lezioni in totale.

Cosa imparerò in «functools: lru_cache e cached_property»?

Memorizzi nella cache i calcoli costosi con lru_cache e cached_property. Eserciti Python Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Python Academy?

Non è richiesta alcuna esperienza precedente. Python Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «functools: lru_cache e cached_property»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Python Academy?

Sì. Ogni lezione Python Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. itertools: iteratori infiniti e finiti
  2. itertools: calcolo combinatorio
  3. functools: partial e reduce
  4. functools: lru_cache e cached_property
← Torna a Python Academy