更新类的属性时清除某些方法的 lru_cache?

agi*_*iap 5 python synchronization caching lru functools

我有一个带有 method/property 的对象multiplier。这个方法在我的程序中被调用了很多次,所以我决定使用lru_cache()它来提高执行速度。正如预期的那样,它要快得多:

以下代码显示了问题:

from functools import lru_cache

class MyClass(object):
    def __init__(self):
        self.current_contract = 201706
        self.futures = {201706: {'multiplier': 1000},
                        201712: {'multiplier': 25}}

    @property
    @lru_cache()
    def multiplier(self):
        return self.futures[self.current_contract]['multiplier']

CF = MyClass()
assert CF.multiplier == 1000

CF.current_contract = 201712
assert CF.multiplier == 25
Run Code Online (Sandbox Code Playgroud)

第二个assert失败,因为缓存值为 1000,因为lru_cache()不知道底层属性current_contract已更改。

更新 self.current_contract 时有没有办法清除缓存?

谢谢!

bru*_*ers 6

是的,很简单:创建current_contract一个读/写属性并清除属性设置器中的缓存:

from functools import lru_cache

class MyClass(object):
    def __init__(self):
        self.futures = {201706: {'multiplier': 1000},
                        201712: {'multiplier': 25}}
        self.current_contract = 201706

    @property
    def current_contract(self):
        return self._current_contract

    @current_contract.setter
    def current_contract(self, value):
        self._current_contract = value
        type(self).multiplier.fget.cache_clear()

    @property
    @lru_cache()
    def multiplier(self):
        return self.futures[self.current_contract]['multiplier']
Run Code Online (Sandbox Code Playgroud)

注意:我假设您的实际用例涉及昂贵的计算,而不仅仅是字典查找 - 否则lru_cache可能有点矫枉过正;)

  • 如果你有这样的优化需求,你可能想在 `multiplier` 中使用 `self._current_contract` 而不是 `self.current_contract`(以避免属性调用/方法调用/属性解析开销),并且可能只是让 multiplier a在 `current_contract` setter 中设置的普通属性(请注意,我没有做过任何基准测试,所以你可能想先用 `timeit` 来找出哪个解决方案确实是最快的) (2认同)