Как кэшировать свойство на уровне класса в Python? - PullRequest
0 голосов
/ 29 октября 2018

Итак, я работаю над Customer class, который должен быть оберткой для некоторых других классов, которые получают информацию о конкретном клиенте с сервера и из Интернета, как показано ниже.

class Customer:
    def __init__(self, name):
        self.name = name

    @property
    @lru_cache()
    def online_info(self):
       print('retrieving customer online info')
       return Online().search_result(for=self)

    @property
    @lru_cache()
    def server_info(self):
      print('retrieving customer server info')
      return Server().search_result(for=self)

Онлайн и серверные звонки должны быть оформлены @property. Проблема, с которой я сталкиваюсь, заключается в попытке кэшировать вызовы online_info и server_info. Так или иначе, кэш должен находиться на уровне класса, так что даже если создается экземпляр клиента новостей, lru_cache будет помнить предыдущие вызовы из других экземпляров для вызова с тем же именем. Обратите внимание на мои печатные заявления. Вот то, чего я пытаюсь добиться:

>>> cutomer1 = Customer('John')
>>> customer1.online_info
retrieving customer online info
John Smith has the following info bla bla bla ....

>>> cutomer2 = Customer('John')
>>> customer2.online_info # this one will not be calling the function, lru_cache will return the value saved from customer1.online_info
John Smith has the following info bla bla bla ....

Может кто-нибудь объяснить, как мне добиться этого поведения? Это возможно?

1 Ответ

0 голосов
/ 29 октября 2018

Вместо кэширования значений свойств в классе, я бы рекомендовал повторно использовать один и тот же экземпляр Customer для каждого "Джона", чтобы

>>> Customer('John') is Customer('John')
True

Это сделало бы Customer своего рода синглтоном. В этом вопросе можно найти множество реализаций синглтона: Создание синглтона в Python . Заимствование одной из этих реализаций дает нам псевдо-синглтонный метакласс, подобный этому:

class NameSingleton(type):
    def __init__(cls, *args, **kwargs):
        cls._instances = {}

    def __call__(cls, name, *args, **kwargs):
        try:
            return cls._instances[name]
        except KeyError:
            instance = super().__call__(name, *args, **kwargs)
            cls._instances[name] = instance
            return instance

Используйте это как метакласс для Customer и все готово:

class Customer(metaclass=NameSingleton):
    def __init__(self, name):
        self.name = name

    ...

Демо-версия:

>>> Customer('John') is Customer('John')
True
>>> Customer('John') is Customer('not John')
False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...