文字列ではなく、データ構造全体の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
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
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
私は自分でそれを書くことになりました。
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()
更新:キーの順序がランダムであるため、これは辞書では機能しません。申し訳ありません、私は考えていません。
import hashlib
import cPickle as pickle
data = ['anything', 'you', 'want']
data_pickle = pickle.dumps(data)
data_md5 = hashlib.md5(data_pickle).hexdigest()
これは、すべてのpythonデータ構造、およびオブジェクトでも機能します。
組み込みの pprint を使用すると、提案されているjson.dumps()
ソリューションよりも多くのケースをカバーできます。たとえば、datetime
- objectsは正しく処理されます。
あなたの例は、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
ROCKYの方法:構造体のすべての項目を1つの親エンティティ(まだ存在しない場合)に配置し、再帰して並べ替え/正規化などを行い、repr
のmd5を計算します。
joblib
への依存関係は必要ですが、 joblib.hashing.hash(object)
は非常にうまく機能し、joblib
のディスクキャッシュで使用するように設計されていることがわかりました機構。経験的には、異なる実行でpickle
が混同するデータであっても、実行ごとに一貫した結果を生成しているようです。
または、artemis-ml
's compute_fixed_hash
関数。理論的には、実行全体で一貫した方法でオブジェクトをハッシュします。しかし、私はそれを自分でテストしていません。
元の質問から何百万年も投稿されて申し訳ありません????