问题
I'm looking for a way to cache properties of an object. In my case, I suppose the object can change over the time, so the memoized value for the property should be flushable. In pure python, I want to have a behaviour like:
class Foo:
def __init__(self, text: str):
self._text = text
self._bar = None
def flush(self):
self._bar = None
def update_text(self, text: str):
self._text = text
self.flush()
@property
def bar(self):
if self._bar is None:
print('Computing bar...')
self._bar = f'Computation with "{self._text}".'
return self._bar
foo1 = Foo('Dog')
foo2 = Foo('Fish')
print(foo1.bar)
# Computing bar...
# Computation with "Dog".
print(foo1.bar)
# Computation with "Dog".
print(foo2.bar)
# Computing bar...
# Computation with "Fish".
print(foo2.bar)
# Computation with "Fish".
foo1.update_text('Cat')
print(foo1.bar)
# Computing bar...
# Computation with "Cat".
print(foo1.bar)
# Computation with "Cat".
print(foo2.bar)
# Computation with "Fish".
Then, as you can see, I want to cache the Foo.bar
property. My approach was to define a private property initialised as None
and then assigned and flushed to obtain a memoized behaviour.
Now, my question is if there is some method, library, approach or technique to obtain this behaviour without the need to have a private property (imagine you have tends of memoizable properties in the class).
I was reading about the @lru_cache()
decorator (and the newest @cached_property
) from the Standard Library (https://docs.python.org/3/library/functools.html), but I realised that the cache_clear()
method removes the memoized values for all the instances of the class.
I was thinking that one possible solution could be to use immutable objects, but that solution is not as I want, because probably there will be situations in which I only want to flush one of the properties memoization.
回答1:
Thanks to @sanyash discussion on question comments.
There is a cached_property
package (https://pypi.org/project/cached-property/) that provides the requested behaviour. The example using cached_property
is as follows:
from cached_property import cached_property
class Foo:
def __init__(self, text: str):
self._text = text
def flush(self):
del self.__dict__['bar']
def update_text(self, text: str):
self._text = text
self.flush()
@cached_property
def bar(self):
print('Computing bar...')
return f'Computation with "{self._text}".'
foo1 = Foo('Dog')
foo2 = Foo('Fish')
print(foo1.bar)
# Computing bar...
# Computation with "Dog".
print(foo1.bar)
# Computation with "Dog".
print(foo2.bar)
# Computing bar...
# Computation with "Fish".
print(foo2.bar)
# Computation with "Fish".
foo1.update_text('Cat')
print(foo1.bar)
# Computing bar...
# Computation with "Cat".
print(foo1.bar)
# Computation with "Cat".
print(foo2.bar)
# Computation with "Fish".
回答2:
cached_property
is the perfect solution to cache properties.
If you have similar concern about functions, methodtools works for each instances.
import methodtools
class Foo:
@methodtools.lru_cache(maxsize=128)
def bar(self, a, b, c):
return something_using_parameters
来源:https://stackoverflow.com/questions/58471400/is-there-an-easy-way-to-memoize-and-flush-properties-on-python-at-object-level