In my attempt to achieve a class level cache decorator, I have stumbled across the ring
library which is able to save a function's inputs an outputs globally. It basically allows me to achieve the following behavior, given the class
definition of Calculate
as below:
import ring
class Calculate:
@ring.dict({})
def sum(self, a, b):
print('actually calculating')
sum = a + b
return sum
this is the behavior I am trying to achieve with Calculate
>>> calculate = Calculate()
>>> calcualte.sum(5,7)
actually calculating
12
>>> different_calculate = Calculate()
>>> different_calculate.sum(5,7)
12 #this outputs 12 straight from the cache from first calculate.
#Note that even if 'different_calculate' and 'calculate' are different instantiations of 'Calculate', the cache works at a class level. Therefore the sum is not actually REcalculated.
Now, I need to achieve the same behavior with sum
, this time being a property. The issue that I am facing here is that in a @property
def
takes as argument self
. Therefore, when trying to cache as in the previous example it will not work, because the input is no longer num1
and num2
, but self
, which changes with every instantiation. Therefore it will never pull from cache on a different class instantiation, as self always changes with every instantiation. See below:
import ring
class Calculate:
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
@ring.dict({})
@property
def sum(self):
print('actually calculating')
sum = num1 + num2
return sum
>>> calculate = Calculate()
>>> calcualte.sum(5,7)
actually calculating
12
>>> different_calculate = Calculate()
>>> different_calculate.sum(5,7)
actually calculating
12
To solve this problem, I somehow have to tell the cache library not to look at self
as input, but at self.num1
, self.num2
. The code will then nee to be something like this:
@ring.dict(self.num1, self.num2) # <--- this does not exist
@property
def sum(self):
print('actually calculating')
sum = num1 + num2
return sum
Is there any way I can do this with ring
, or any other python cache library for that matter?
So after getting some inspiration from here, I ended up just creating my own memoization function, as so:
memo = {}
def memoize(*attrs):
def wrapper(f):
def helper(obj):
key = tuple([getattr(obj,attr) for attr in attrs])
if key not in memo:
memo[key] = f(obj)
return memo[key]
return helper
return wrapper
class Calculate:
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
@property
@memoize('num1', 'num2')
def sum(self):
print('actually calculating')
sum = self.num1 + self.num2
return sum
>>> calculate = Calculate(6,9)
>>> calculate.sum
actually calculating
15
>>> another_calculate = Calculate(6,9)
>>> another_calculate.sum
15