为了缓存函数(现在我正在使用klepto),我将一个配置对象cfg
传递给函数s.t.仅在cfg
更改时计算返回值。
cfg
必须是可以播放的hash(cfg1) == hash(cfg2)
cfg1 == cfg2
。cfg.para1
。dict
和list
是cfg
中唯一不可取的对象。我想做这样的事情:
from klepto import lru_cache
from klept.keymaps import hasher
class MyClass:
def __init__(self, cfg)
self.cfg = cfg
def my_func(self):
return self._my_func(self.cfg)
@lru_cache(keymap=hasher, ignore=(self,))
def _my_func(self, cfg):
a = cfg.a
b = cfg.b.c[0]
return expensive_func(a, b)
cfg_dic = {
'a': 1,
'b': {'c': [1,2,3]}
}
cfg = give_me_the_hashable_object_i_need(cfg_dic)
my_obj = MyClass(cfg)
my_obj.my_func() #evaluate only if cfg was not (recently) used before
使用包python-box中的Box()
对象,由常规(嵌套)python dict cfg_dic
初始化:
from box import Box
cfg = Box(cfg_dic, frozen_box=True, box_it_up=True)
在初始化OrderedDicts
之前,从dic
及其条目(在将其转换为元组的元组之后,......)中生成Box
:
from collections import OrderedDict
from box import Box
def to_tuple(dic_or_list):
l = []
if isinstance(dic_or_list, list):
for v in sorted(dic_or_list):
try:
hash(v)
l.append(v)
except TypeError:
l.append(to_tuple(v))
elif isinstance(dic_or_list, dict):
for k, v in sorted(dic_or_list.items()):
try:
hash(v)
l.append((k, v))
except TypeError:
l.append((k, to_tuple(v)))
else:
raise ValueError('argument must be one of "dict", "list"')
return tuple(l)
def second_level_odict(tup):
if len(tup) == 2:
k_1, v_1 = tup
if isinstance(v_1, tuple):
for v_2 in v_1:
if len(v_2) != 2:
return (k_1, v_1)
return (k_1, (OrderedDict(v_1)))
else:
return (k_1, v_1)
else:
return tup
def first_level_odict(tup):
l = []
for t in tup:
l.append(second_level_odict(t))
return OrderedDict(l)
tup = to_tuple(dic)
odic = first_level_odict(tup)
cfg = Box(odic, frozen_box=True, box_it_up=True)
放弃box
并使dict可以播放。
class hashabledict(dict):
def __hash__(self):
return hash(tuple(sorted(self.items())))
class hashablelist(list):
def __hash__(self):
return hash(tuple(sorted(self)))
def make_hashable(dic):
for k, v in dic.items():
if isinstance(v, dict):
dic[k] = hashabledict(v)
elif isinstance(v, list):
dic[k] = hashablelist(v)
return hashabledict(dic)
我还尝试将cfg
Box()
作为带有排序键的json-string传递:
def my_func(self):
return self._my_func(self.cfg.to_json(sort_keys=True))
@lru_cache(keymap=hasher, ignore=(self,))
def _my_func(self, cfg_string):
cfg = Box().from_json(cfg_string)
a = cfg.a
b = cfg.b.c[0]
return expensive_func(a, b)
所有这些都失败了,因为(例如在重新启动IPython内核之后),虽然条目相同,但散列不同。
我愿意接受任何建议,非常感谢!