17

为字典内容生成唯一键的最佳方法是什么。我的目的是将每个字典与唯一的 id 或哈希一起存储在文档存储中,这样我就不必从存储中加载整个字典来检查它是否已经存在。具有相同键和值的字典应该生成相同的 id 或 hash。

我有以下代码:

import hashlib

a={'name':'Danish', 'age':107}
b={'age':107, 'name':'Danish'}

print str(a)
print hashlib.sha1(str(a)).hexdigest()
print hashlib.sha1(str(b)).hexdigest()

最后两个打印语句生成相同的字符串。这是一个很好的实现吗?或者这种方法有什么陷阱吗?有一个更好的方法吗?

更新

结合以下答案的建议,以下可能是一个很好的实现

import hashlib

a={'name':'Danish', 'age':107}
b={'age':107, 'name':'Danish'}


def get_id_for_dict(dict):
    unique_str = ''.join(["'%s':'%s';"%(key, val) for (key, val) in sorted(dict.items())])
    return hashlib.sha1(unique_str).hexdigest()

print get_id_for_dict(a)
print get_id_for_dict(b)
4

3 回答 3

39

我更喜欢将 dict 序列化为 JSON 并对其进行哈希处理:

import hashlib
import json

a={'name':'Danish', 'age':107}
b={'age':107, 'name':'Danish'}

# Python 2
print hashlib.sha1(json.dumps(a, sort_keys=True)).hexdigest()
print hashlib.sha1(json.dumps(b, sort_keys=True)).hexdigest()

# Python 3
print(hashlib.sha1(json.dumps(a, sort_keys=True).encode()).hexdigest())
print(hashlib.sha1(json.dumps(b, sort_keys=True).encode()).hexdigest())

回报:

71083588011445f0e65e11c80524640668d3797d
71083588011445f0e65e11c80524640668d3797d
于 2013-11-07T19:13:50.787 回答
7

不 -在将字典转换为字符串时,您不能依赖特定的元素顺序

但是,您可以将其转换为 (key,value) 元组的排序列表,将其转换为字符串并计算如下所示的哈希:

a_sorted_list = [(key, a[key]) for key in sorted(a.keys())]
print hashlib.sha1( str(a_sorted_list) ).hexdigest()

这不是万无一失的,因为转换为字符串的列表格式或元组格式可能会在未来的某些主要 python 版本中发生变化,排序顺序取决于语言环境等,但我认为它已经足够好了。

于 2013-04-18T21:01:28.147 回答
3

一个可能的选择是使用保留顺序的列表的序列化表示。我不确定字符串机制的默认列表是否强加任何类型的顺序,但如果它依赖于解释器,我不会感到惊讶。所以,我基本上会预先构建类似于对urlencode键进行排序的东西。

并不是说我相信你的方法会失败,而是我宁愿玩可预测的事情并避免无证和/或不可预测的行为。诚然,尽管“无序”,字典最终的顺序甚至可能是一致的,但关键是你不应该认为这是理所当然的。

于 2013-04-18T20:38:23.343 回答