Evp*_*pok 22 python dictionary python-3.x hashable
我有一个方法,其中(以及其他)字典作为参数.该方法是解析字符串,字典提供了一些子字符串的替换,因此它不必是可变的.
这个函数经常被调用,而且在冗余元素上,所以我认为缓存它会提高它的效率.
但是,正如你可能已经猜到的那样,因为它dict是可变的,因而不能清洗,@functools.lru_cache所以无法装饰我的功能.那我怎么能克服这个呢?
如果只需要标准的库类和方法,则可以获得奖励积分.理想情况下,如果它存在某种frozendict标准库,我还没有看到它会成为我的一天.
PS:namedtuple只有最后的手段,因为它需要大的语法转换.
如何创建一个dict像这样的可散列类:
class HDict(dict):
def __hash__(self):
return hash(frozenset(self.items()))
substs = HDict({'foo': 'bar', 'baz': 'quz'})
cache = {substs: True}
Run Code Online (Sandbox Code Playgroud)
这是一个使用@mhyfritz技巧的装饰器.
def hash_dict(func):
"""Transform mutable dictionnary
Into immutable
Useful to be compatible with cache
"""
class HDict(dict):
def __hash__(self):
return hash(frozenset(self.items()))
@functools.wraps(func)
def wrapped(*args, **kwargs):
args = tuple([HDict(arg) if isinstance(arg, dict) else arg for arg in args])
kwargs = {k: HDict(v) if isinstance(v, dict) else v for k, v in kwargs.items()}
return func(*args, **kwargs)
return wrapped
Run Code Online (Sandbox Code Playgroud)
只需在lru_cache之前添加它.
@hash_dict
@functools.lru_cache()
def your_function():
...
Run Code Online (Sandbox Code Playgroud)
与其使用自定义的可哈希字典,不如使用它,避免重新发明轮子!这是一本冻结的字典,都是可哈希的。
https://pypi.org/project/frozendict/
码:
def freezeargs(func):
"""Transform mutable dictionnary
Into immutable
Useful to be compatible with cache
"""
@functools.wraps(func)
def wrapped(*args, **kwargs):
args = tuple([frozendict(arg) if isinstance(arg, dict) else arg for arg in args])
kwargs = {k: frozendict(v) if isinstance(v, dict) else v for k, v in kwargs.items()}
return func(*args, **kwargs)
return wrapped
Run Code Online (Sandbox Code Playgroud)
然后
@freezeargs
@lru_cache
def func(...):
pass
Run Code Online (Sandbox Code Playgroud)
代码来自@fast_cen的答案
注意:这不适用于递归数据结构;例如,您可能有一个参数列表,这是不可哈希的。邀请您进行包装的递归,这样包装就可以深入数据结构并制作每个dict冻结的list元组。
(我知道OP不再需要解决方案,但我来这里是寻找相同的解决方案,因此将其留给后代使用)