If hashing doesn't work for you can try to take advantage of the internal state of your class.
Cache one method
Use a class attribute as a cache: on first call of the method, store the result into this attribute, and retrieve it on subsequent call.
import pandas as pd class MyClass: def __init__(self, *args, **kwargs): self._df = pd.DataFrame(*args, **kwargs) self._cached_value = None @property def df(self): return self._df @df.setter def df(self, value): self._cached_value = None self._df = value @property def derived(self): if self._cached_value is None: self._cached_value = self._df.sum(axis=1) return self._cached_value cl = MyClass() cl.derived # compute cl.derived # return cached value cl.df = my_new_df_value # cache is emptied cl.derived # compute
Cache several methods
You can then extend this principle to several methodes using a dict to store the result of each operation. You can use methods name as the keys to this dict (thanks to module inspect, see this response for an example).
import pandas as pd import inspect class MyClass: def __init__(self, *args, **kwargs): self.df = pd.DataFrame(*args, **kwargs) self._cached_values = {} @property def derived(self): method_name = self._get_method_name() if method_name not in self._cached_values: self._cached_value[method_name] = self.df.sum(axis=1) return self._cached_value[method_name] @property def derived_bis(self): method_name = self._get_method_name() if method_name not in self._cached_values: self._cached_value[method_name] = your_expensive_op return self._cached_value[method_name] def _get_method_name(self): return inspect.stack()[1][3] # returns the name of this method's caller cl = MyClass() cl.derived # compute --> self._cached_value = {'derived': your_result} cl.derived # return cached value cl.derived_bis # compute --> self._cached_value = {'derived': your_result, 'derived_bis': your_other_result} cl.derived_bis # return cached value
You can factorize the bodies of the two properties to respect the DRY principle, but be sure to modify _get_method_name accordingly.
derivedin the case whereself.dfwas not changed?derivedoperation or do you wish to have a system that you can extend to some other operations on this dataframe ?