0Pricing
Python Academy · Урок

functools: lru_cache и cached_property

Кэшируйте ресурсоёмкие вычисления с помощью lru_cache и cached_property.

«functools: lru_cache и cached_property» — бесплатный урок Python Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.

Что такое мемоизация?

Мемоизация кэширует результат вызова функции, используя её аргументы как ключ. Повторные вызовы с теми же аргументами сразу возвращают кэшированный результат.

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) кэширует до maxsize последних результатов. Установите maxsize=None для кэша без ограничения размера.

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 — это сокращённая запись для lru_cache(maxsize=None): кэш без ограничения размера с более понятным именем.

import functools

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

print(factorial(10))  # 3628800

Информация о кэше и его очистка

Кэшированные функции предоставляют .cache_info() (попадания, промахи и размер) и .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

LRU (наименее недавно использованный) при заполнении кэша удаляет элемент, к которому обращались давнее всего.

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)

Только хешируемые аргументы

lru_cache требует, чтобы все аргументы были хешируемыми. Списки и словари нельзя хешировать; вместо них используйте кортежи.

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 вычисляет свойство один раз и кэширует результат в экземпляре, заменяя дескриптор значением.

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

@property выполняет вычисление при каждом обращении. @cached_property вычисляет значение один раз и сохраняет результат в 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))

Потокобезопасность cached_property

cached_property не является потокобезопасным. Если несколько потоков обращаются к нему одновременно, вычисление может выполниться более одного раза. При необходимости используйте блокировку.

import functools, threading

class SafeCache:
    _lock = threading.Lock()

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

Инвалидация cached_property

Удалите атрибут экземпляра, чтобы сделать кэш недействительным и принудительно выполнить вычисление при следующем обращении.

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

Использование lru_cache как кэша API

Кэшируйте ответы API в течение сеанса, чтобы избежать повторных сетевых запросов. Очищайте кэш, когда требуются свежие данные.

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

Быстрая проверка

Какой метод очищает все кэшированные результаты функции, оформленной декоратором @lru_cache?

Итоги

@lru_cache кэширует результаты функций, используя аргументы как ключи (аргументы должны быть хешируемыми). @cache — это псевдоним для кэша без ограничения размера. @cached_property кэширует вычисление свойства для каждого экземпляра. Просматривайте кэш с помощью cache_info() и сбрасывайте его с помощью cache_clear().

Часто задаваемые вопросы

Урок «functools: lru_cache и cached_property» бесплатный?

Да — полный текст урока «functools: lru_cache и cached_property» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.

Чему я научусь в уроке «functools: lru_cache и cached_property»?

Кэшируйте ресурсоёмкие вычисления с помощью lru_cache и cached_property. Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Python Academy?

Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «functools: lru_cache и cached_property»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Python Academy?

Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. itertools: бесконечные и конечные итераторы
  2. itertools: комбинаторика
  3. functools: partial и reduce
  4. functools: lru_cache и cached_property
← Назад к Python Academy