I think you could do it automatically, but I usually think it's better to talk about a "lazy" rating. Therefore, I will present a method of adding an additional argument in your memoized functions lazy. But instead of files, pickle and md5 I’ll simplify the helpers a bit:
storage = {}
def calculate_md5(obj):
print('calculating md5 of', obj)
return hash(obj)
def create_file(md5, data):
print('creating file for md5', md5)
storage[md5] = data
def load_file(md5):
print('loading file with md5 of', md5)
return storage[md5]
I use a custom class as an intermediate object:
class MemoizedObject(object):
def __init__(self, md5):
self.md5 = result_md5
def get_real_data(self):
print('load...')
return load_file(self.md5)
def __repr__(self):
return '{self.__class__.__name__}(md5={self.md5})'.format(self=self)
, , Memoize, , :
class Memoize(object):
def __init__(self, func):
self.func = func
self.md5_to_md5_storage = {}
def __call__(self, x, lazy=False):
if isinstance(x, MemoizedObject):
key = x.md5
else:
key = calculate_md5(x)
if lazy and key in self.md5_to_md5_storage:
return MemoizedObject(self.md5_to_md5_storage[key])
elif not lazy and key in self.md5_to_md5_storage:
result = load_file(self.md5_to_md5_storage[key])
else:
result = self.func(x)
result_md5 = calculate_md5(result)
create_file(result_md5, result)
self.md5_to_md5_storage[key] = result_md5
return result
, "" , () :
@Memoize
def f(x):
return x+1
@Memoize
def g(x):
return x+2
() :
>>> x1 = 10
>>> y1 = f(x1)
calculating md5 of 10
calculating md5 of 11
creating file for md5 11
>>> y2 = g(y1)
calculating md5 of 11
calculating md5 of 13
creating file for md5 13
lazy:
>>> x1 = 10
>>> y1 = f(x1)
calculating md5 of 10
loading file with md5 of 11
>>> y2 = g(y1)
calculating md5 of 11
loading file with md5 of 13
lazy=True
>>> x1 = 10
>>> y1 = f(x1, lazy=True)
calculating md5 of 10
>>> y2 = g(y1)
loading file with md5 of 13
"md5" . , .