0Pricing
Python Academy · Lekcja

functools: lru_cache i cached_property

Proszę buforować kosztowne obliczenia za pomocą lru_cache i cached_property.

functools: lru_cache i cached_property to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.

Czym jest memoizacja?

Memoizacja przechowuje wynik wywołania funkcji pod kluczem utworzonym z jej argumentów. Kolejne wywołania z tymi samymi argumentami natychmiast zwracają wynik z pamięci podręcznej.

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) przechowuje w pamięci podręcznej do maxsize ostatnich wyników. Ustawienie maxsize=None tworzy cache bez ograniczenia rozmiaru.

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 to skrócona forma lru_cache(maxsize=None) — nieograniczona pamięć podręczna o czytelniejszej nazwie.

import functools

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

print(factorial(10))  # 3628800

Informacje o pamięci podręcznej i jej czyszczenie

Funkcje z pamięcią podręczną udostępniają metody .cache_info() (trafienia, chybienia, rozmiar) oraz .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()

Zasada usuwania LRU

LRU (Least Recently Used) usuwa element, do którego najdawniej uzyskano dostęp, gdy pamięć podręczna jest pełna.

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)

Tylko argumenty haszowalne

lru_cache wymaga, aby wszystkie argumenty były haszowalne. Listy i słowniki nie są haszowalne, dlatego należy używać krotek.

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 oblicza właściwość raz i zapisuje wynik w instancji, zastępując deskryptor wartością.

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

@property ponownie oblicza wartość przy każdym dostępie. @cached_property oblicza ją raz i zapisuje wynik w 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))

Bezpieczeństwo wątkowe cached_property

cached_property nie jest bezpieczne wątkowo. Jeśli wiele wątków uzyska do niego dostęp jednocześnie, obliczenie może zostać wykonane więcej niż raz. W razie potrzeby należy użyć blokady.

import functools, threading

class SafeCache:
    _lock = threading.Lock()

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

Unieważnianie cached_property

Aby unieważnić pamięć podręczną i wymusić ponowne obliczenie przy następnym dostępie, należy usunąć atrybut instancji.

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

Używanie lru_cache jako pamięci podręcznej API

Odpowiedzi API można przechowywać w pamięci podręcznej na czas sesji, aby uniknąć zbędnych wywołań sieciowych. Pamięć podręczną należy wyczyścić, gdy potrzebne są aktualne dane.

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

Szybkie sprawdzenie

Jaka metoda usuwa wszystkie wyniki z pamięci podręcznej funkcji udekorowanej za pomocą @lru_cache?

Podsumowanie

@lru_cache przechowuje wyniki funkcji pod kluczami utworzonymi z argumentów, które muszą być haszowalne. @cache jest aliasem bez ograniczenia rozmiaru. @cached_property przechowuje wynik obliczenia właściwości osobno dla każdej instancji. Stan można sprawdzić za pomocą cache_info(), a pamięć zresetować za pomocą cache_clear().

Często zadawane pytania

Czy lekcja „functools: lru_cache i cached_property” jest bezpłatna?

Tak — pełny tekst „functools: lru_cache i cached_property” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „functools: lru_cache i cached_property”?

Proszę buforować kosztowne obliczenia za pomocą lru_cache i cached_property. Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Python Academy?

Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „functools: lru_cache i cached_property”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?

Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. itertools: iteratory nieskończone i skończone
  2. itertools: kombinatoryka
  3. functools: partial i reduce
  4. functools: lru_cache i cached_property
← Powrót do Python Academy