我想计算一个不是字符串的md5哈希,而是整个数据结构。我理解一种方法的机制(对值的类型进行调度,规范化字典键顺序和其他随机性,递归到子值等)。但这似乎是一种通常有用的操作,所以我很惊讶我需要自己动手。
在Python中有没有更简单的方法来实现这个目标?
更新:pickle已被建议,这是一个好主意,但酸洗不规范字典键顺序:
>>> import cPickle as pickle
>>> import hashlib, random
>>> for i in range(10):
... k = [i*i for i in range(1000)]
... random.shuffle(k)
... d = dict.fromkeys(k, 1)
... p = pickle.dumps(d)
... print hashlib.md5(p).hexdigest()
...
51b5855799f6d574c722ef9e50c2622b
43d6b52b885f4ecb4b4be7ecdcfbb04e
e7be0e6d923fe1b30c6fbd5dcd3c20b9
aebb2298be19908e523e86a3f3712207
7db3fe10dcdb70652f845b02b6557061
43945441efe82483ba65fda471d79254
8e4196468769333d170b6bb179b4aee0
951446fa44dba9a1a26e7df9083dcadf
06b09465917d3881707a4909f67451ae
386e3f08a3c1156edd1bd0f3862df481
答案 0 :(得分:61)
json.dumps()可以按键对字典进行排序。所以你不需要其他依赖项:
import hashlib
import json
data = ['only', 'lists', [1,2,3], 'dictionaries', {'a':0,'b':1}, 'numbers', 47, 'strings']
data_md5 = hashlib.md5(json.dumps(data, sort_keys=True)).hexdigest()
print(data_md5)
打印:
87e83d90fc0d03f2c05631e2cd68ea02
答案 1 :(得分:23)
bencode对词典进行排序:
import hashlib
import bencode
data = ['only', 'lists', [1,2,3],
'dictionaries', {'a':0,'b':1}, 'numbers', 47, 'strings']
data_md5 = hashlib.md5(bencode.bencode(data)).hexdigest()
print data_md5
打印:
af1b88ca9fd8a3e828b40ed1b9a2cb20
答案 2 :(得分:7)
我结束了自己写作,因为我认为我必须:
class Hasher(object):
"""Hashes Python data into md5."""
def __init__(self):
self.md5 = md5()
def update(self, v):
"""Add `v` to the hash, recursively if needed."""
self.md5.update(str(type(v)))
if isinstance(v, basestring):
self.md5.update(v)
elif isinstance(v, (int, long, float)):
self.update(str(v))
elif isinstance(v, (tuple, list)):
for e in v:
self.update(e)
elif isinstance(v, dict):
keys = v.keys()
for k in sorted(keys):
self.update(k)
self.update(v[k])
else:
for k in dir(v):
if k.startswith('__'):
continue
a = getattr(v, k)
if inspect.isroutine(a):
continue
self.update(k)
self.update(a)
def digest(self):
"""Retrieve the digest of the hash."""
return self.md5.digest()
答案 3 :(得分:3)
更新:由于密钥顺序随机性,这对字典不起作用。对不起,我没想到。
import hashlib
import cPickle as pickle
data = ['anything', 'you', 'want']
data_pickle = pickle.dumps(data)
data_md5 = hashlib.md5(data_pickle).hexdigest()
这适用于任何python数据结构,也适用于对象。
答案 4 :(得分:0)
ROCKY方式:将所有结构项放在一个父实体中(如果还没有),递归并排序/规范化/等等,然后计算其repr
的md5。
答案 5 :(得分:0)
尽管确实需要依赖于joblib
,但我发现joblib.hashing.hash(object)
的运行非常好,并且设计用于joblib
的磁盘缓存机制。从经验上看,即使pickle
在不同的运行中混合在一起的数据,每次运行似乎都能产生一致的结果。
或者,您可能对artemis-ml
的{{3}}函数感兴趣,该函数在理论上以跨运行一致的方式对对象进行哈希处理。但是,我还没有亲自测试过。
很抱歉在原始问题后发布了数百万年
答案 6 :(得分:0)
您可以使用内置的pprint来解决比建议的json.dumps()
解决方案更多的情况。例如,datetime
-对象将得到正确处理。
您的示例重写为使用pprint
而不是json
:
>>> import hashlib, random, pprint
>>> for i in range(10):
... k = [i*i for i in range(1000)]
... random.shuffle(k)
... d = dict.fromkeys(k, 1)
... print hashlib.md5(pprint.pformat(d)).hexdigest()
...
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db
b4e5de6e1c4f3c6540e962fd5b1891db