Python,dict的校验和

Python,dict的校验和,python,checksum,Python,Checksum,我想创建一个dict的校验和,以知道它是否被修改 目前我有: >>> import hashlib >>> import pickle >>> d = {'k': 'v', 'k2': 'v2'} >>> z = pickle.dumps(d) >>> hashlib.md5(z).hexdigest() '8521955ed8c63c554744058c9888dc30' 也许有更好的解决办法 注意:我

我想创建一个dict的校验和,以知道它是否被修改 目前我有:

>>> import hashlib
>>> import pickle
>>> d = {'k': 'v', 'k2': 'v2'}
>>> z = pickle.dumps(d)
>>> hashlib.md5(z).hexdigest()
'8521955ed8c63c554744058c9888dc30'
也许有更好的解决办法

注意:我想创建一个dict的唯一id来创建一个好的Etag


编辑:我可以在目录中包含抽象数据。

我不知道
pickle
是否保证每次都以相同的方式序列化哈希

如果您只有字典,我会选择o组合调用
keys()
sorted()
,基于排序的键/值对构建一个字符串,并计算该键/值对的校验和,如下所示:

reduce(lambda x,y : x^y, [hash(item) for item in d.items()])
获取dict中每个(键、值)元组的散列,并将它们全部异或

@卡布里埃尔·亚历克斯 如果dict包含不易损坏的项目,您可以执行以下操作:

hash(str(d))
或者更好

hash(repr(d))

正如您所说的,您希望基于字典内容生成一个Etag,它保留字典的顺序,在这里可能是更好的选择。只需遍历键、值对并构造Etag字符串。

我认为您可能没有意识到其中的一些微妙之处。第一个问题是,dict中项目的显示顺序没有由实现定义。这意味着简单地请求dict的
str
是不起作用的,因为你可以

str(d1) == "{'a':1, 'b':2}"
str(d2) == "{'b':2, 'a':1}"
这些将散列到不同的值。如果dict中只有可散列的项,那么可以对它们进行散列,然后将它们的散列连接起来,就像这样做或简单地连接一样

hash(tuple(sorted(hash(x) for x in d.items())))
请注意排序后的
,因为您必须确保哈希元组以相同的顺序出现,而不管条目在dict中出现的顺序如何。如果dict中有dict,则可以递归此操作,但这会很复杂

但是,如果您允许字典中包含任意数据,那么很容易破坏任何这样的实现,因为您可以简单地编写一个具有破坏的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您不能使用
id
,因为这样您可能会有相同的项比较不同的项


这个故事的寓意是,Python不支持哈希指令是有原因的。

在Python 3中,哈希函数是用一个随机数初始化的,每个Python会话都不同。如果预期应用不可接受,则使用例如zlib.adler32为dict建立校验和:

import zlib

d={'key1':'value1','key2':'value2'}
checksum=0
for item in d.items():
    c1 = 1
    for t in item:
        c1 = zlib.adler32(bytes(repr(t),'utf-8'), c1)
    checksum=checksum ^ c1

print(checksum)

我建议采用与您提议的方法非常相似的方法,但有一些额外的保证:

import hashlib, json
hashlib.md5(json.dumps(d, sort_keys=True, ensure_ascii=True).encode('utf-8')).hexdigest()
  • sort\u keys=True
    :如果密钥顺序发生变化,请保留相同的哈希值
  • 确保_ascii=True
    :如果您有一些非ascii字符,请确保表示形式不变

我们将其用于ETag。

“”。在排序(foo.iteritems())中加入(“%s,%s”%(x,y)代表x,y)
(其中foo是dict)可能用作签名,您可以对其进行哈希。如果我的dict中有抽象数据,该怎么办?这不是问题吗?我想你需要做一个递归函数来序列化每个子结构的排序数据。如果dict包含dict呢?因此,我说需要递归函数——主dict中包含的每个dict都应该像主dict一样对待——它的键基于此进行排序和序列化dict包含什么?如果只是字符串(比如说),您可以对排序后的字符串表示进行散列:
hash(repr(sorted(my_dict.items())))
。什么是抽象数据?dict哈希算法的稳定性和工作稳定性在很大程度上取决于它所保存的数据。例如,如果您有一个dict的dict怎么办?这些数据类型:如果dict包含不可损坏的项怎么办?如果没有假阴性,您就不能执行
str(d)
,因为这些项在字符串表示中出现的顺序是未定义的。我运行了一个测试,在两个字典中添加了1000000个键/值对,但顺序不同,不会导致假阴性(str(d1)=str(d2)总是正确的)。我认为你是对的,但变化很小。这对于缓存来说可能已经足够了。使用repr(d)会给出一个定义的顺序吗?我认为repr()也取决于dict的内部顺序。如果不进行
排序(d.iteritems())
@agf:你绝对是对的!但是第一个解决方案(reduce()
东西)将散列与XOR结合起来,从而丢弃元素的顺序。