2009-08-24 15 views
9

Existe-t-il un moyen de générer un ID de type hachage pour les objets dans Python qui est uniquement basé sur les valeurs d'attribut des objets? Par exemple,Générer un ID unique pour l'objet python en fonction de ses attributs

class test: 
    def __init__(self, name): 
     self.name = name 

obj1 = test('a') 
obj2 = test('a') 

hash1 = magicHash(obj1) 
hash2 = magicHash(obj2) 

Ce que je cherche est quelque chose où hash1 == hash2. Est-ce que quelque chose comme ça existe en python? Je sais que je peux tester si obj1.name == obj2.name, mais je cherche quelque chose de général que je peux utiliser sur n'importe quel objet.

Répondre

6

Vous voulez dire quelque chose comme ça? En utilisant la méthode spéciale __hash__

class test: 
    def __init__(self, name): 
     self.name = name 
    def __hash__(self): 
     return hash(self.name) 

>>> hash(test(10)) == hash(test(20)) 
False 
>>> hash(test(10)) == hash(test(10)) 
True 
+2

Cependant, ce n'est pas garanti d'être unique. –

+0

@Bastien, vous avez raison. Mais cela dépend vraiment de l'application. Dans de nombreux cas, le hash pourrait suffire. –

+1

Il n'est pas recommandé de renvoyer quoi que ce soit de __hash __ (self) en plus d'un int (http://docs.python.org/reference/datamodel.html#object.__hash__), car cela rendra l'objet apparemment non utilisable (comme dans utilisé dans les dicts) – SingleNegationElimination

3

Pour obtenir une comparaison unique:

Pour être unique, vous pouvez sérialiser les données et comparer la valeur sérialisée pour assurer qu'elle correspond exactement.

Exemple:

import pickle 

class C: 
    i = 1 
    j = 2 

c1 = C() 
c2 = C() 
c3 = C() 
c1.i = 99 

unique_hash1 = pickle.dumps(c1) 
unique_hash2 = pickle.dumps(c2) 
unique_hash3 = pickle.dumps(c3) 

unique_hash1 == unique_hash2 #False 
unique_hash2 == unique_hash3 #True 

Si vous n'avez pas besoin des valeurs uniques pour chaque objet, mais surtout unique:

Notez la même valeur sera toujours réduire au même hachage, mais deux différents les valeurs pourraient réduire au même hachage.

Vous ne pouvez pas utiliser quelque chose comme la fonction de hachage() intégrée (sauf si vous substituez __hash__)

hash(c1) == hash(c2) #False 
hash(c2) == hash(c3) #False <--- Wrong 

ou quelque chose comme sérialiser les données en utilisant cornichon, puis utilisez zlib.crc32.

import zlib 
crc1 = zlib.crc32(pickle.dumps(c1)) 
crc2 = zlib.crc32(pickle.dumps(c2)) 
crc3 = zlib.crc32(pickle.dumps(c3)) 
crc1 == crc2 #False 
crc2 == crc3 #True 
+0

Pour la comparaison unique, vous pouvez également utiliser zlib.compress pour rendre la représentation un peu plus petite si vos objets sont très gros. –

+0

Non, le cornichon n'est pas bon pour le hachage. Les résultats peuvent varier, comme décrit par Robert Brewer: http://www.aminus.org/blogs/index.php/2007/11/03/pickle_dumps_not_suitable_for_hashing?blog=2 –

+0

Je ne sais pas pourquoi mais avec CPython 2.5.1 I ne peut pas reproduire son comportement. Il hash toujours au même résultat pour moi. –

2

Je suppose que

def hash_attr(ins): 
return hash(tuple(ins.__dict__.items())) 

hachages instance de quoi que ce soit en fonction de ses attributs.

+1

Tant que tous les attributs sont lavables. –

Questions connexes