繁体   English   中英

如何从 @cached_property 装饰器中清除缓存?

[英]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.cachelru_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM