2009-08-24 15 views
9

C'è un modo per generare un ID hash come in per gli oggetti in pitone che si basa esclusivamente su valori degli attributi degli oggetti? Ad esempio,Genera ID univoco per oggetto Python sulla base di suoi attributi

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

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

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

Quello che sto cercando è qualcosa in cui hash1 == hash2. Esiste qualcosa come questo in Python? So di poter verificare se obj1.name == obj2.name, ma sto cercando qualcosa di generale posso usare su qualsiasi oggetto.

risposta

6

Vuoi dire qualcosa di simile? Utilizzando il metodo speciale __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

non è garantito per essere unico però. –

+0

@Bastien, hai ragione. Ma questo dipende davvero dall'applicazione. Per molti casi l'hash potrebbe essere sufficiente. –

+1

Non è consigliato restituire nulla da __hash __ (self) oltre a un int (http://docs.python.org/reference/datamodel.html#object.__hash__) in quanto ciò renderà l'oggetto apparentemente ma non correttamente lavabile (come in utilizzato in dicts) – SingleNegationElimination

3

Per ottenere un confronto unico nel suo genere:

per essere unico è possibile serializzare i dati e quindi confrontare il valore serializzato per assicurarsi che corrisponda esattamente.

Esempio:

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 

Se non avete bisogno di valori unici per ogni oggetto, ma soprattutto unico nel suo genere:

nota lo stesso valore sarà sempre ridurre al stesso hash, ma 2 differenti i valori potrebbero ridurre allo stesso hash.

Non si può usare qualcosa come la funzione built-in hash() (a meno che non si ignora __hash__)

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

o qualcosa di simile serializzare i dati con salamoia e poi usare 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

Per il confronto univoco puoi anche usare zlib.compress per rendere la rappresentazione un po 'più piccola se i tuoi oggetti sono molto grandi –

+0

No, pickle non va bene per l'hashing. I risultati possono variare, come descritto da Robert Brewer: http://www.aminus.org/blogs/index.php/2007/11/03/pickle_dumps_not_suitable_for_hashing?blog=2 –

+0

Non so perché ma con CPython 2.5.1 I non può riprodurre il suo comportamento. Ha sempre lo stesso risultato per me. –

2

immagino

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

hash esempio nulla sulla base dei suoi attributi.

+1

Fintanto che tutti gli attributi sono lavabili .. –