如何在python中在类级别缓存属性?

如何在python中在类级别缓存属性?,python,python-3.x,class,caching,properties,Python,Python 3.x,Class,Caching,Properties,因此,我正在开发一个Customer类,它应该是一些其他类的包装器,这些类从服务器和在线检索特定客户的信息,如下所示 class Customer: def __init__(self, name): self.name = name @property @lru_cache() def online_info(self): print('retrieving customer online info') return

因此,我正在开发一个
Customer类
,它应该是一些其他类的包装器,这些类从服务器和在线检索特定客户的信息,如下所示

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
修饰的。我面临的问题是在尝试缓存
联机信息
服务器信息
调用时。缓存必须位于类级别,这样即使实例化了一个新闻客户,
lru\u缓存
wold也会记住来自其他实例化的相同名称调用的先前调用。注意我的打印声明。这就是我试图实现的行为:

>>> 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 ....

有人能解释一下我是如何做到这一点的吗?这可能吗?

我建议对每个“John”重新使用相同的
Customer
实例,而不是缓存类上的属性值,以便

这将使
Customer
成为某种类型的单身汉。在这个问题中可以找到大量的单例实现:。借用其中一个实现,我们可以得到一个伪单例元类,如下所示:

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

    ...
演示:


如果我做了
客户('not John')。在线信息
?这也应该使用缓存值吗?@Aran Fey在这种情况下不,因为“no John”以前从未被调用过你不能在属性上使用
lru缓存
,或者至少,即使你的装饰程序顺序正确(现在是不正确的),在那里使用
lru缓存也没有意义
lru\u cache
通过查看函数的参数来工作,这里您所拥有的只是。。。无,因为属性不接受参数。@Aran Fey,如果您有另一个客户(“no John”)。在线信息,在初始“no John”之后,第二个“no John”的值将从缓存中提取,而不是从属性中提取call@MartijnPieters那是不对的。这里有一个
self
参数。如果装饰器被交换,代码工作得非常好。这是一个有趣的构建。然而,我有点不愿意使用这段代码,因为在链的上游,我从一个pandas数据帧创建了多个客户,然后在多个线程上调用服务器信息和在线信息,我担心使用单线程和多线程时,它们可能会在每个线程上出错other@callmeGuy好,可能发生的最糟糕的事情是,两个线程同时创建一个John,并以两个不同的John实例结束。但是,无论您是在缓存
Customer
实例还是属性值,每个缓存机制都有这个问题。如果这是一个问题,您可以将
Customer
构造函数包装为一个。因此,如果我在同一时间创建了两个客户,并且它们恰好具有相同的值,那么缓存将毫无用处。有全局缓存吗?@callmeGuy这是一个全局缓存,但它不是线程安全的。它只需要一把锁。
class Customer(metaclass=NameSingleton):
    def __init__(self, name):
        self.name = name

    ...
>>> Customer('John') is Customer('John')
True
>>> Customer('John') is Customer('not John')
False