我正在尝试在使用__slots__
属性定义的类中缓存计算量很大的属性。
任何想法,如何存储缓存供以后使用?当然,如果没有定义instance._cache
,在__dict__
中存储字典的常用方法将无效。由于多种原因,我不想将'_cache'
字符串添加到__slots__
。
我在想这是否是全球罕见的用例之一。关于此事的任何想法或例子?
答案 0 :(得分:2)
你不需要全球化;您可以将缓存存储为类属性,并将昂贵的属性定义为property
。
class Foo(object):
__slots__ = ('a', 'b', 'c')
expensive_cache = {}
@property
def expensive(self):
if self not in self.expensive_cache:
self.expensive_cache[self] = self._compute_expensive()
return self.expensive_cache[self]
def _compute_expensive(self):
print("Computing expensive property for {}".format(self))
return 3
f = Foo()
g = Foo()
print(f.expensive)
print("===")
print(f.expensive)
print("===")
print(g.expensive)
如果您运行此代码,则可以看到_compute_expensive
仅在您第一次访问每个不同对象的expensive
时运行一次。
$ python3 tmp.py
Computing expensive property for <__main__.Foo object at 0x102861188>
3
===
3
===
Computing expensive property for <__main__.Foo object at 0x1028611c8>
3
答案 1 :(得分:2)
那里没有魔法 - 你想存储一个值,所以你需要一个存储价值的地方。
您不能只决定“我的__slots__
上没有额外的条目,因为它不优雅” - 您无需将其称为_cached
:
给它你想要的任何名称,但这些缓存的值是你想要存在于每个对象的实例中的东西,因此你需要一个属性。
您可以在全局(模块级别)字典中缓存,其中密钥为id(self)
- 但在删除实例时保持同步是一个非常令人头疼的问题。 (对于类级别的字典也是如此,它的进一步缺点仍然在实例上可见。)
TL; DR :“一种显而易见的方法”是拥有一个shadow属性,以“_”开头以保留您想要缓存的值,并在{{ 1}}。 (如果每个实例使用一个__slots__
字典,则会失去_cached
的主要优势,即每个实例不需要一个字典。)
答案 2 :(得分:-2)
像Borg模式这样的东西可以提供帮助。
您可以使用__init__
或__new__
方法更改实例的状态。