Search code examples
pythoncachingsynchronizationfunctoolslru

Clearing lru_cache of certain methods when an attribute of the class is updated?


I have an object with a method/property multiplier. This method is called many times in my program, so I've decided to use lru_cache() on it to improve the execution speed. As expected, it is much faster:

The following code shows the problem:

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

The 2nd assert fails, because the cached value is 1000 as lru_cache() is unaware that the underlying attribute current_contract was changed.

Is there a way to clear the cache when self.current_contract is updated?

Thanks!


Solution

  • Yes quite simply: make current_contract a read/write property and clear the cache in the property's setter:

    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']
    

    NB : I assume your real use case involves costly computations instead of a mere dict lookup - else lru_cache might be a bit overkill ;)