TL; DR:
Fare riferimento al glossario : hash()viene utilizzato come scorciatoia per confrontare oggetti, un oggetto è considerato hash se può essere confrontato con altri oggetti. ecco perché usiamo hash(). E 'anche usato per l'accesso dicte setgli elementi che vengono implementati come tabelle hash ridimensionabili in CPython .
Considerazioni tecniche
- di solito il confronto di oggetti (che può coinvolgere diversi livelli di ricorsione) è costoso.
- preferibilmente, la
hash()funzione è un ordine di grandezza (o più) meno costosa.
- confrontare due hash è più facile che confrontare due oggetti, è qui che si trova il collegamento.
Se leggi come sono implementati i dizionari , usano tabelle hash, il che significa che derivare una chiave da un oggetto è una pietra angolare per il recupero di oggetti nei dizionari in formato O(1). Tuttavia, dipende molto dalla tua funzione hash per essere resistente alle collisioni . Il caso peggiore per ottenere un elemento in un dizionario è in realtà O(n).
In questa nota, gli oggetti modificabili di solito non sono modificabili. La proprietà hashable significa che puoi usare un oggetto come chiave. Se il valore hash viene utilizzato come chiave e il contenuto dello stesso oggetto cambia, cosa dovrebbe restituire la funzione hash? È la stessa chiave o un'altra? Esso dipende da come si definisce la funzione di hash.
Imparare con l'esempio:
Immagina di avere questa classe:
>>> class Person(object):
... def __init__(self, name, ssn, address):
... self.name = name
... self.ssn = ssn
... self.address = address
... def __hash__(self):
... return hash(self.ssn)
... def __eq__(self, other):
... return self.ssn == other.ssn
...
Nota: tutto questo si basa sul presupposto che il SSN non cambia mai per un individuo (non so nemmeno dove verificare effettivamente quel fatto da fonte autorevole).
E abbiamo Bob:
>>> bob = Person('bob', '1111-222-333', None)
Bob va a vedere un giudice per cambiare il suo nome:
>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')
Questo è quello che sappiamo:
>>> bob == jim
True
Ma questi sono due oggetti diversi con una memoria allocata diversa, proprio come due record diversi della stessa persona:
>>> bob is jim
False
Ora arriva la parte in cui hash () è utile:
>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'
Indovina un po:
>>> dmv_appointments[jim]
'tomorrow'
Da due record differenti è possibile accedere alle stesse informazioni. Ora prova questo:
>>> dmv_appointments[hash(jim)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in __eq__
AttributeError: 'int' object has no attribute 'ssn'
>>> hash(jim) == hash(hash(jim))
True
Cosa è appena successo? È una collisione. Poiché hash(jim) == hash(hash(jim))sono entrambi numeri interi, dobbiamo confrontare l'input di __getitem__con tutti gli elementi che entrano in collisione. Il builtin intnon ha un ssnattributo quindi scatta.
>>> del Person.__eq__
>>> dmv_appointments[bob]
'tomorrow'
>>> dmv_appointments[jim]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: <__main__.Person object at 0x7f611bd37110>
In questo ultimo esempio, mostro che anche con una collisione, il confronto viene eseguito, gli oggetti non sono più uguali, il che significa che solleva con successo a KeyError.