Комментарии 14
Вообще-то нет. Описанный по ссылке антипаттерн возникает, если полагать, что массив/словарь инициализируется заново в каждом вызове функции:
A programmer wrote the append function below under the assumption that the append function would return a new list every time that the function is called without the second argument. In reality this is not what happens.
А описанный здесь приём основывается как раз на том, что значение будет общим для всех вызовов.
Еще один минус предложенной идеи — из внешнего вида функции ни как не следует, кэшируется ее результат или нет, что, теоретически, может приводить к неожиданным эффектам в коде, где эта функция используется. Для целей кэширования результатов функции лучше использовать другие, более очевидные, методы.
Вам почти наверняка придется что — то придумывать, если вы будете активно использовать этот прием, чтобы посмотреть, какой кэш и сколько памяти занял, потому что уверенности, что любая среда разработки способна переварить такой кейс, нет никакой.
Насчёт неочевидности кэширования и отсутствия контроля за памятью согласен, в теории такой кэш может без предупреждения разрастись на несколько гиг. Метод хорош в более-менее недолго работающих программах (в моём случае научные расчёты, которым надо отработать максимум три-четыре раза по сутки каждый за исследование), но оставлять такую функцию бесконечно крутиться на сервере не стоит.
Насчёт интерфейса не согласен, потому что публичный интерфейс функции никак не отличается от некэшируемого аналога. Новые аттрибуты не появляются, старые не удаляются. У любой функции есть __defaults__
, у любой функции в него можно залезть. Разве что у некэшируемой меньше вероятность найти там что-то интересное, но и тут эксплицитное обращение к function.__defaults__[0][query_value]
не нормальный интерфейс, а хак вокруг хака.
Ошибся веткой
@functools.lru_cache. Декоратор из модуля functools, который запоминает последние вызовы функции. Надёжно и просто, но использует в качестве ключей все параметры функции, а значит, требует их хэшируемости и не может заметить, что два формально разных значения параметра эквивалентны.
А у вас разве как-то иначе? Вы тоже используете значения как ключи словаря, что требует, чтобы они были hashable.
if a not in cache:
cache[a] = a*a
Мемоизация дефолтным kwarg в Python