计算数据结构的 md5 哈希值

问题描述 投票:0回答:8

我想计算不是字符串的 md5 哈希值,而是整个数据结构的 md5 哈希值。我了解执行此操作的方法的机制(分派值的类型、规范化字典键顺序和其他随机性、递归到子值等)。但这似乎是一种通常有用的操作,所以我很惊讶我需要自己进行此操作。

Python 有没有更简单的方法来实现这一点?

更新:已经建议使用pickle,这是一个好主意,但是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
python data-structures md5
8个回答
104
投票

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).encode('utf-8')).hexdigest()

print(data_md5)

打印:

87e83d90fc0d03f2c05631e2cd68ea02

33
投票

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

8
投票

我最终自己写了它,因为我认为我必须这样做:

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

6
投票

您可以使用内置的 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

3
投票

更新:由于按键顺序随机性,这不适用于字典。抱歉,我还没想到。

import hashlib
import cPickle as pickle
data = ['anything', 'you', 'want']
data_pickle = pickle.dumps(data)
data_md5 = hashlib.md5(data_pickle).hexdigest()

这应该适用于任何 Python 数据结构,也适用于对象。


2
投票

虽然它确实需要依赖于

joblib
,但我发现
joblib.hashing.hash(object)
工作得非常好,并且设计用于与
joblib
的磁盘缓存机制一起使用。根据经验,它似乎在每次运行中都会产生一致的结果,即使数据在不同的运行中混合在一起。

或者,您可能对

pickle

artemis-ml
 函数感兴趣,理论上该函数以跨运行一致的方式对对象进行哈希处理。不过我自己没有测试过。
抱歉在最初的问题发生数百万年后才发布😅


0
投票
compute_fixed_hash

的 md5。

    


0
投票

这是我对 @webwurst 答案的修订版本,它以块的形式生成 JSON 字符串,这些字符串立即用于计算最终校验和,以防止大对象消耗过多的内存:

repr

© www.soinside.com 2019 - 2024. All rights reserved.