为了缓存目的,我需要从字典中存在的GET参数生成一个缓存键。

目前,我正在使用sha1(repr(sorted(my_dict.items()))) (sha1()是一个内部使用hashlib的方便方法),但我很好奇是否有更好的方法。


当前回答

您可以使用地图库来做到这一点。具体来说,地图。FrozenMap

import maps
fm = maps.FrozenMap(my_dict)
hash(fm)

要安装地图,只需执行:

pip install maps

它也处理嵌套的dict大小写:

import maps
fm = maps.FrozenMap.recurse(my_dict)
hash(fm)

免责声明:我是地图库的作者。

其他回答

如果你的字典不是嵌套的,你可以用字典的项创建一个frozenset,并使用hash():

hash(frozenset(my_dict.items()))

与生成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))  

使用sorted(d.s items())并不足以获得稳定的repr。d中的一些值也可以是字典,它们的键仍然会以任意顺序出现。只要所有的键都是字符串,我更喜欢使用:

json.dumps(d, sort_keys=True)

也就是说,如果散列需要在不同的机器或Python版本之间保持稳定,我不确定这是万无一失的。您可能希望添加分隔符和ensure_ascii参数,以保护自己不受对默认值的任何更改的影响。我很感激你的评论。

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()

我是这样做的:

hash(str(my_dict))