Создайте отдельный словарь в замыкании декоратора и сохраняйте результат по ключу аргументов. Проверка наличия ключа, а не истинности результата, позволяет кешировать None, 0 и False.
Кеширующий декоратор: замыкание и сохранение None, 0, False
Создайте отдельный словарь в замыкании декоратора и сохраняйте результат по ключу аргументов. Проверка наличия ключа, а не истинности результата, позволяет кешировать None, 0 и False.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Написать код для функции cache. Это декоратор, который должен
запоминать, что вернула декорированная функция, и возвращать запомненное
значение при повторном вызове с одинаковыми аргументами.
Можно считать, что все аргументы хешируемые.
Использовать только стандартную библиотеку Python.
def cache(func): raise NotImplementedError
calls = {"count": 0}
@cache def add(a, b): calls["count"] += 1 return a + b
assert add(1, 2) == 3 assert calls["count"] == 1
assert add(1, 2) == 3 assert calls["count"] == 1
assert add(2, 3) == 5 assert calls["count"] == 2
print("OK")
Ответ
Создайте отдельный словарь в замыкании декоратора и сохраняйте результат по ключу аргументов. Проверка наличия ключа, а не истинности результата, позволяет кешировать None, 0 и False.
from functools import wraps
def cache(func):
values = {}
@wraps(func)
def wrapped(*args, **kwargs):
key = (args, tuple(sorted(kwargs.items())))
if key not in values:
values[key] = func(*args, **kwargs)
return values[key]
return wrapped
Для тестов из условия счётчик будет равен 2. Ошибки не кешируются. Эквивалентные позиционные и именованные вызовы могут получить разные ключи. В production учитывайте ограничение размера, изменяемые результаты и конкурентный доступ; для простых случаев есть functools.cache.