Проверка sentinel перевёрнута: возвращать result нужно при result is not _SANTINEL. Сейчас первый вызов возвращает служебный объект вместо вычисления, поэтому первый assert падает.
Перевёрнутая проверка sentinel в кеше Python
Проверка sentinel перевёрнута: возвращать result нужно при result is not _SANTINEL. Сейчас первый вызов возвращает служебный объект вместо вычисления, поэтому первый assert падает.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Можно считать, что все аргументы хешируемые.
Использовать только стандартную библиотеку Python.
_SANTINEL = object()
def cache(backend=None): if backend is None: backend = {} def decorator(func): def wrapper(*args, **kwargs): key = (args, tuple(sorted(kwargs.items()))) result = backend.get(key, _SANTINEL) if result is _SANTINEL: return result result = func(*args, **kwargs) backend[key] = result return result return wrapper return decorator
calls = {"count": 0} backend = {}
@cache(backend=backend) 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 len(backend) == 1 print("OK")
Ответ
Проверка sentinel перевёрнута: возвращать result нужно при result is not _SANTINEL. Сейчас первый вызов возвращает служебный объект вместо вычисления, поэтому первый assert падает.
from functools import wraps
_SENTINEL = object()
def cache(backend=None):
if backend is None:
backend = {}
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = (args, tuple(sorted(kwargs.items())))
result = backend.get(key, _SENTINEL)
if result is not _SENTINEL:
return result
result = func(*args, **kwargs)
backend[key] = result
return result
return wrapper
return decorator
Проверка backend is None сохраняет переданный пустой словарь. Для общего backend нескольких функций нужен отдельный namespace в ключе, иначе одинаковые аргументы столкнутся. Для данного примера одной функции после двух вызовов остаётся одна запись.