Кэширование функций при изменении свойства объекта

У меня есть функция, которую мне нужно кэшировать. Аргументы функции — это объект obj среди прочих. Однако я хотел бы периодически менять свойство объекта obj.

Я пробовал использовать functools lru_cache.

class TestObj:
    def __init__(self, number):
        self.number = number

@lru_cache(1024)
def print_number(obj):
    return obj.number

obj = TestObj(1)


assert print_number(obj) == 1
obj.number = 2
assert print_number(obj) == 2

Я бы хотел, чтобы вторым утверждением утверждения было true, так как я изменил базовое свойство объекта obj

Это не имеет никакого смысла. Вы можете просто написать obj.number вместо print_number(obj). Можете ли вы придумать лучший пример?

Aran-Fey 20.06.2019 13:18
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
88
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш пример в значительной степени противоречит цели lru_cache.. Во всяком случае, единственный способ, который я могу придумать, это добавить print_number.cache_clear() перед вашим вторым утверждением:

assert print_number(obj) == 1
obj.number = 2
print_number.cache_clear()
assert print_number(obj) == 2

Спасибо и извините за упрощенный пример.

AKE 20.06.2019 16:58
Ответ принят как подходящий

Это общая проблема с изменяемыми объектами. Какую бы систему кэширования вы ни использовали, цель кэша — вернуть предыдущее значение (без его вычисления) при задании тех же параметров.

Здесь вы фактически передаете тот же самый объект (настоящая идентичность, заданная is в Python), поэтому ни одна система кэширования не может догадаться, что ее кеш грязный. Вот распространенные обходные пути:

  • извлекать объект из кеша сразу после его изменения. Здесь это будет означать, что number должно быть свойством и что TestObj должно знать о кеше. тут не все так просто ИМХО
  • не кэшируйте print_number, а сделайте его оболочкой вокруг другой функции, вызывающей соответствующие неизменяемые члены TestObj. Тривиально здесь

Вам придется

def print_number(obj):
    return do_print_number(obj.number)


@lru_cache(1024)
def do_print_number(number):
    return number

Это будет работать при условии, что obj.number является неизменяемым объектом, например, числом, строкой или кортежем, а не списком, набором или картой.

Спасибо за ваш подробный ответ.

AKE 20.06.2019 16:58

Другие вопросы по теме