![](/img/trans.png)
[英]Difference between @cached_property and @lru_cache decorator
[英]How do I clear the cache from @cached_property decorator?
我有一个名为“值”的 function 进行大量计算......
如果没有更改标识符的数据集,则 function 的结果始终相同。
一旦数据集更改为某个标识符,我想清除缓存,并让 function 再次计算它。
通过查看以下代码,您可以更好地理解我:
from functools import cached_property
class Test:
identifiers = {}
dataset = an empty object of dataset type
def __init__(self, identifier, ...)
self.identifier = identifier
...
Test.identifiers[identifier] = self
...
@cached_property
def value(self):
result = None
# heavy calculate based on dataset
return result
@classmethod
def get(cls, identifier):
if identifier in cls.identifiers:
return cls.identifiers[identifier]
else:
return cls(identifier, ...)
@classmethod
def update(cls, dataset):
for block in dataset:
# assume there is block['identifier'] in each block
# here i want to clear the cache of value() function
instance = cls.get(block['identifier'])
# clear @cached_property of instance
cls.dataset.append(block)
正如您在CPython 源代码中看到的那样,Python 3.8 中的cached_property
的值存储在同名的实例变量中。 这没有记录,因此它可能是您不应该依赖的实现细节。
但是,如果您只想完成它而不考虑兼容性,则可以使用del instance.value
删除缓存。 谁知道呢,也许将来会记录当前的行为,因此在任何版本或解释器实现中使用它都是安全的。
(上一个答案的补充)
如果您修改 object 并且您需要重新加载@cached_property
(因为 object 已被变异)您可以删除已经缓存在self.__dict__
字典中的属性(这是缓存属性的位置)
from functools import cached_property
class Test:
datalist: List[int]
@cached_property
def value(self):
result = None
# heavy calculate based on datalist
return result
def add_element(self, new:int)-> None:
# restore cache if calculated
self.__dict__.pop('value', None) # this will delete the cached val
self.datalist.append(new)
我提供了一种替代方法,在某些情况下可能有用。 如果需要进行计算的数据集类型是可散列的,则可以使用常规的functools.cache
或lru_cache
装饰器,应用于将数据集作为输入的 static 方法。
这是我的意思的一个例子:
from functools import lru_cache
class MyClass():
def __init__(self, data):
self.data = data
@property
def slow_attribute(self):
return self._slow_attribute(self.data)
@staticmethod
@lru_cache
def _slow_attribute(data):
# long computation, using data,
# here is just an example
return sum(data)
这里不需要关心何时清除缓存:如果底层数据集发生变化,静态方法会自动知道它不能再使用缓存的值。
这有额外的好处,如果数据集要恢复到以前使用的 state,查找可能仍然能够使用缓存值。
这是上面工作的代码的演示:
from time import perf_counter_ns
def print_time_and_value_of_computation(c):
t1 = perf_counter_ns()
val = c.slow_attribute
t2 = perf_counter_ns()
print(f'Time taken: {(t2 - t1)/1000} microseconds')
print(f'Value: {val}')
c = MyClass(range(10_000))
print_time_and_value_of_computation(c)
print_time_and_value_of_computation(c)
print('Changing the dataset!')
c.data = range(20_000)
print_time_and_value_of_computation(c)
print_time_and_value_of_computation(c)
print('Going back to the original dataset!')
c.data = range(10_000)
print_time_and_value_of_computation(c)
返回:
Time taken: 162.074 microseconds
Value: 49995000
Time taken: 2.152 microseconds
Value: 49995000
Changing the dataset!
Time taken: 264.121 microseconds
Value: 199990000
Time taken: 1.989 microseconds
Value: 199990000
Going back to the original dataset!
Time taken: 1.144 microseconds
Value: 49995000
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.