为了缓存目的,我需要从字典中存在的GET参数生成一个缓存键。
目前,我正在使用sha1(repr(sorted(my_dict.items()))) (sha1()是一个内部使用hashlib的方便方法),但我很好奇是否有更好的方法。
为了缓存目的,我需要从字典中存在的GET参数生成一个缓存键。
目前,我正在使用sha1(repr(sorted(my_dict.items()))) (sha1()是一个内部使用hashlib的方便方法),但我很好奇是否有更好的方法。
当前回答
如果你的字典不是嵌套的,你可以用字典的项创建一个frozenset,并使用hash():
hash(frozenset(my_dict.items()))
与生成JSON字符串或字典表示相比,这需要的计算量要小得多。
更新:请参阅下面的评论,为什么这种方法可能不会产生稳定的结果。
其他回答
MD5哈希
对我来说,产生最稳定结果的方法是使用md5哈希和json.stringify
from typing import Dict, Any
import hashlib
import json
def dict_hash(dictionary: Dict[str, Any]) -> str:
"""MD5 hash of a dictionary."""
dhash = hashlib.md5()
# We need to sort arguments so {'a': 1, 'b': 2} is
# the same as {'b': 2, 'a': 1}
encoded = json.dumps(dictionary, sort_keys=True).encode()
dhash.update(encoded)
return dhash.hexdigest()
为了保持键顺序,而不是哈希(str(字典))或哈希(json.dumps(字典)),我更喜欢快速和肮脏的解决方案:
from pprint import pformat
h = hash(pformat(dictionary))
它甚至可以用于DateTime等不能序列化的JSON类型。
这里有一个更清晰的解决方案。
def freeze(o):
if isinstance(o,dict):
return frozenset({ k:freeze(v) for k,v in o.items()}.items())
if isinstance(o,list):
return tuple([freeze(v) for v in o])
return o
def make_hash(o):
"""
makes a hash out of anything that contains only list,dict and hashable types including string and numeric types
"""
return hash(freeze(o))
解决这个问题的一种方法是用字典的元素创建一个元组:
hash(tuple(my_dict.items()))
您可以使用地图库来做到这一点。具体来说,地图。FrozenMap
import maps
fm = maps.FrozenMap(my_dict)
hash(fm)
要安装地图,只需执行:
pip install maps
它也处理嵌套的dict大小写:
import maps
fm = maps.FrozenMap.recurse(my_dict)
hash(fm)
免责声明:我是地图库的作者。