Как реализовать кэширование с functools.lru_cache?python-35

lru_cache (Least Recently Used cache) — это декоратор из модуля functools, который реализует мемоизацию (memoization) функций, сохраняя результаты вызовов для избежания повторных вычислений.

Основные принципы работы

1. Базовое использование

Декоратор запоминает возвращаемые значения функции для определенных аргументов:

from functools import lru_cache

@lru_cache
def fibonacci(n: int) -> int:
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Без кэширования сложность O(2ⁿ), с кэшем — O(n).

2. Параметры настройки

  • maxsize: максимальное количество хранимых результатов (по умолчанию 128)
  • typed: раздельное кэширование для разных типов (False по умолчанию)
@lru_cache(maxsize=256, typed=True)
def calculate(x: float, y: float) -> float:
    return x**2 + y**2

Практические примеры

1. Кэширование запросов к API

import requests

@lru_cache(maxsize=100)
def get_user_data(user_id: int):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json()

2. Кэширование парсинга конфигурации

@lru_cache
def parse_config(file_path: str) -> dict:
    with open(file_path) as f:
        return json.load(f)

Особенности работы

1. Требования к аргументам

Аргументы должны быть хешируемыми (hashable). Для нехешируемых аргументов можно использовать преобразование:

@lru_cache
def process_data(data_tuple: tuple):
    # data_tuple - неизменяемая версия данных
    pass

2. Очистка кэша

fibonacci.cache_clear()  # Полная очистка кэша

3. Просмотр статистики

cache_info = fibonacci.cache_info()
print(f"Hit: {cache_info.hits}, Miss: {cache_info.misses}")

Ограничения

  1. Неизменяемые аргументы: параметры должны поддерживать хеширование
  2. Побочные эффекты: не подходит для функций с побочными эффектами
  3. Изменяемые объекты: напрямую не работает со списками/словарями

Альтернативы

  1. functools.cache: неограниченный кэш (Python 3.9+)
  2. cachetools: более продвинутые варианты кэширования

Резюмируем

lru_cache идеально подходит для:

  • Рекурсивных функций (Фибоначчи, факториал)
  • Тяжелых вычислений
  • Чтения конфигураций
  • Запросов к внешним ресурсам

Пример с подсветкой (VSCode style):

from functools import lru_cache

@lru_cache(maxsize=32)
def get_weather(city: str, country: str) -> dict:
    # Имитация запроса к API погоды
    print(f"Fetching weather for {city}, {country}")
    return {
        "city": city,
        "country": country,
        "temperature": 25.5  # Пример данных
    }