所以我正在开发一个
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 ....
有人可以解释我如何实现这种行为吗?这可能吗?
我建议为每个“John”重新使用相同的
Customer
实例,而不是缓存类上的属性值,这样
>>> Customer('John') is Customer('John')
True
这将使
Customer
成为某种单例。在这个问题中可以找到大量的单例实现:Creating a singleton in 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
假设您想要使用您提供的调用模式:您需要实例的“属性”属性,这些属性在获取时会返回由
self.name
标识的客户的信息。但您希望在类范围内缓存客户信息,因此如果您创建具有相同 self.name
的两个实例,则两个实例之间不会重复工作。
在我看来,你想要的是一个“属性”属性,其 fget 函数调用类方法,并且类方法缓存其结果。
此代码实现了该模式
import functools
class Customer:
def __init__(self, name):
self.name = name
@property
def info(self):
print('retrieving info 1 for', self.name)
return Customer.info_implement(self.name)
@classmethod
@functools.cache
def info_implement(cls, name):
print('retrieving info 2 for', name)
return "info for " + name
customer1 = Customer('John')
print("customer1 info", customer1.info)
print("customer1 info", customer1.info)
customer2 = Customer('John')
print("customer2 info", customer2.info)
print("customer2 info", customer2.info)
并产生这个输出
retrieving info 1 for John
retrieving info 2 for John
customer1 info info for John
retrieving info 1 for John
customer1 info info for John
retrieving info 1 for John
customer2 info info for John
retrieving info 1 for John
customer2 info info for John