Декоратор кэширования Python: ограничение веса и вытеснение по FIFO
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Декораторы Python: задачи на retry, rate limiter, кэш и Circuit Breaker.
Кэш с учетом веса и вытеснением по FIFO
Модуль рендеринга графических текстур сохраняет сгенерированные буферы в оперативной памяти. Вместо привычного подсчёта количества записей система следит за суммарным бюджетом вычислительной сложности: для каждого набора параметров специальная функция вычисляет затраты в положительных целых условных единицах. Параметризованный декоратор мемоизации принимает предельный бюджет хранилища вместе с этой функцией оценки, удерживая баланс расходов в замыкании.
Когда нужной текстуры нет в памяти, обёртка обращается к оценке затрат. Если вычисление элемента само по себе требует строго больше выделенного предельного бюджета, результат генерируется и возвращается вызывающему коду напрямую, минуя кэш. Если же стоимость укладывается в установленный лимит, декоратор освобождает место: из словаря поочерёдно удаляются самые старые записи в порядке их добавления, пока сумма оставшихся стоимостей вместе со стоимостью нового буфера не станет меньше либо равна предельному бюджету. Лишь после этого результат сохраняется в кэш.
Спроектируйте параметризованный декоратор кэширования, который вытесняет устаревшие записи по балансу бюджета сложности и полностью сохраняет исходную сигнатуру декорируемой функции.
Что уже дано
В заготовке кода представлена функция-заглушка weighted_fifo_cache(budget, cost), которую необходимо реализовать. Вспомогательные классы и проверочные структуры данных доступны во время тестирования, реализовывать их заново не требуется.
Что нужно сделать
Реализуйте функцию weighted_fifo_cache(budget, cost), возвращающую декоратор для синхронных функций.
Параметры фабрики:
budget— неотрицательное целое число от0до1 000 000(включая подклассыint), задающее предельный суммарный вес записей в кэше;cost— синхронная функцияcost(*args, **kwargs), вычисляющая положительный целочисленный вес вызова от1до2 000 000(включая подклассыint) без возбуждения исключений.
Декорируемая функция принимает произвольные хэшируемые аргументы и возвращает любой объект (включая None, False, изменяемые коллекции и подклассы стандартных типов). Декоратор может применяться независимо к нескольким функциям (от 1 до 3) — каждая из них должна обладать собственным изолированным состоянием кэша, лимита и порядка FIFO.
Правила работы обёртки:
- Ключ кэша: формируется по соглашению
(args, tuple(sorted(kwargs.items()))). Порядок передачи именованных аргументов не влияет на ключ. Нормализация значений по умолчанию или позиционных аргументов в именованные не требуется. - Попадание в кэш (hit): возвращается сохранённый объект результата без вызова
costи без вызова декорируемой функции. Порядок FIFO при попадании не обновляется. - Промах (miss):
- Сначала вызывается функция
cost(*args, **kwargs)с исходными аргументами. - Если вычисленный вес строго больше
budget, результат вычисляется целевой функцией и сразу возвращается без сохранения в кэш и без вытеснения уже имеющихся записей. - Если вес не превышает
budget, из кэша поочерёдно удаляются самые старые записи (в порядке их добавления), пока сумма оставшихся весов вместе с весом нового результата не станет меньше либо равнаbudget. Затем вызывается целевая функция, а её результат сохраняется в кэше вместе с его весом.
- Записи, чей вес в точности равен
budget, допустимы для сохранения (при условии полного освобождения остального кэша). - Возвращаемые объекты должны сохранять тождество (
is), включая «ложные» значения (None,False, пустые коллекции). - Обёртка обязана сохранять метаданные декорируемой функции: атрибуты из
functools.WRAPPER_ASSIGNMENTS, сигнатуру интроспекцииinspect.signature, пользовательские атрибуты и ссылку на исходную функцию в__wrapped__.
Ввод и вывод
Стандартные потоки ввода stdin и вывода stdout в решении не используются: считывать ввод и вызывать print() не нужно. После выполнения кода учащегося проверяющая система считывает из пространства имён модуля функцию верхнего уровня weighted_fifo_cache и вызывает её с проверочными аргументами.
Пример использования
calls = []
def cost(name):
return len(name)
@weighted_fifo_cache(4, cost)
def render(name):
calls.append(name)
return name.upper()
print(render("aa"))
print(render("bb"))
print(render("aa"))
print(render("ccc"))
print(render("aa"))
print(calls)
Вывод:
AA
BB
AA
CCC
AA
['aa', 'bb', 'ccc', 'aa']
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Functools.wraps в Python: имя функции и атрибут wrapped
- Декоратор Circuit Breaker на Python: остановка вызовов после сбоев
- Декораторы Python: проверка цепочки wrapped и метаданных функции
- Декоратор Python: логирование только медленных вызовов
- Кэширование Python: постройте ключ из выбранных аргументов функции
- Rate limiter на Python: декоратор со скользящим окном запросов
