web-dev-qa-db-fra.com

Calcul d'un hash md5 d'une structure de données

Je veux calculer un hachage md5 non pas d'une chaîne, mais d'une structure de données complète. Je comprends les mécanismes d'une manière de procéder (dépêche sur le type de la valeur, canoniser l'ordre des clés du dictionnaire et les autres aléas, recurse en sous-valeurs, etc.). Mais cela semble être le genre d'opération qui serait généralement utile, alors je suis surpris de devoir le faire moi-même. 

Existe-t-il un moyen plus simple de réaliser cela?

UPDATE: pickle a été suggéré, et c'est une bonne idée, mais pickling ne canonise pas l'ordre des clés de dictionnaire:

>>> 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
37
Ned Batchelder

bencode trie les dictionnaires ainsi:

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

impressions:

af1b88ca9fd8a3e828b40ed1b9a2cb20
23
Dan D.

json.dumps () peut trier les dictionnaires par clé. Donc, vous n'avez pas besoin d'autres dépendances:

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)

Impressions:

87e83d90fc0d03f2c05631e2cd68ea02
58
webwurst

J'ai fini par l'écrire moi-même car je pensais qu'il me faudrait:

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

UPDATE: cela ne fonctionnera pas pour les dictionnaires en raison du caractère aléatoire de l'ordre des clés. Désolé, je n'y ai pas pensé.

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

Cela devrait fonctionner pour toute structure de données python, ainsi que pour les objets.

3
rvs

Manière ROCKY: Placez tous vos éléments de structure dans une entité parente (si ce n’est pas déjà le cas), recursez-les et triez-les/etc, puis calculez le md5 de sa repr.

0
Hossein

Bien que cela nécessite une dépendance sur joblib, j'ai constaté que joblib.hashing.hash(object) fonctionnait très bien et qu'il était conçu pour être utilisé avec le mécanisme de mise en cache du disque de joblib. De manière empirique, il semble produire des résultats cohérents d'une exécution à l'autre, même sur des données que pickle mélange sur différentes exécutions.

Vous pourriez aussi être intéressé par la fonction artemis-ml ' compute_fixed_hash , qui hache théoriquement les objets de manière cohérente sur toutes les exécutions. Cependant, je ne l'ai pas testé moi-même.

Désolé pour avoir posté des millions d'années après la question initiale ????

0
connor.brinton