Que fait hash en python?
J'ai vu un exemple de code où la fonction hash
est appliquée au tuple. En conséquence, il renvoie un entier négatif. Je me demande ce que fait cette fonction n'. Google n'aide pas. J'ai trouvé une page qui explique comment le hachage est calculé mais cela n'explique pas pourquoi nous avons besoin de cette fonction.
4 réponses
Un hachage est un entier de taille fixe qui identifie une valeur particulière . Chaque valeur doit avoir son propre hachage, donc pour la même valeur, vous obtiendrez le même hachage même si ce n'est pas le même objet.
>>> hash("Look at me!")
4343814758193556824
>>> f = "Look at me!"
>>> hash(f)
4343814758193556824
Les valeurs de hachage doivent être créées de telle sorte que les valeurs résultantes soient réparties uniformément pour réduire le nombre de collisions de hachage que vous obtenez. Les collisions de hachage sont lorsque deux valeurs différentes ont le même hachage. Par conséquent, des changements relativement faibles entraînent souvent des différentes tables de hachage.
>>> hash("Look at me!!")
6941904779894686356
Ces nombres sont très utiles, car ils permettent une recherche rapide des valeurs dans une grande collection de valeurs. Deux exemples de leur utilisation sont set
et dict
de Python. Dans un list
, si vous voulez vérifier si une valeur est dans la liste, avec if x in values:
, Python doit passer par l'ensemble de la liste et de les comparer x
, avec chaque valeur de la liste values
. Cela peut prendre beaucoup de temps pour une longue list
. Dans un set
, Python garde une trace de chaque hachage, et lorsque vous tapez if x in values:
, Python obtiendra le hash-value pour x
, recherchez-le dans une structure interne et comparez uniquement x
avec les valeurs qui ont le même hachage que x
.
La même méthodologie est utilisée pour la recherche de dictionnaire. Cela rend la recherche dans set
et dict
très rapide, tandis que la recherche dans list
est lente. Cela signifie également que vous pouvez avoir non hashable objets dans un list
, mais pas dans un set
ou comme clés dans un dict
. L'exemple typique des objets non hachables est tout objet mutable, ce qui signifie que vous pouvez modifier sa valeur. Si vous avez un objet mutable, il ne devrait pas être hachable, car son hachage changera au cours de sa vie, ce qui causerait beaucoup de confusion, car un objet pourrait se retrouver sous la mauvaise valeur de hachage dans un dictionnaire.
Notez que le hachage d'une valeur ne doit être le même que pour une exécution de Python. En Python 3.3, ils changeront en fait pour chaque nouvelle exécution de Python:
$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21)
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
1849024199686380661
>>>
$ /opt/python33/bin/python3
Python 3.3.2 (default, Jun 17 2013, 17:49:21)
[GCC 4.6.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hash("foo")
-7416743951976404299
C'est à faire est plus difficile de deviner quelle valeur de hachage une certaine chaîne aura, ce qui est important fonctionnalité de sécurité pour les applications web, etc.
Les valeurs de hachage ne doivent donc pas être stockées en permanence. Si vous devez utiliser les valeurs de hachage de manière permanente, vous pouvez jeter un oeil aux types de hachages les plus "sérieux", fonctions de hachage cryptographiques, qui peuvent être utilisées pour faire des sommes de contrôle vérifiables de fichiers, etc.
TL; DR:
, Veuillez vous référer à le glossaire: hash()
est utilisé comme un raccourci pour comparer des objets, un objet est réputé hashable s'il peut être comparé à d'autres objets. c'est pourquoi nous utilisons hash()
. Il est également utilisé pour accéder aux éléments dict
et set
qui sont implémentés en tant que tables de hachage redimensionnables dans CPython .
Considérations Techniques
- généralement comparer des objets (qui peuvent impliquer plusieurs niveaux de récursivité) est coûteux.
- de préférence, la fonction
hash()
est d'un ordre de grandeur (ou plusieurs) moins cher. - comparer deux hachages est plus facile que de comparer deux objets, c'est là que se trouve le raccourci.
Si vous lisez à propos de comment les dictionnaires sont implémentés , ils utilisent des tables de hachage, ce qui signifie que dériver une clé à partir d'un objet est une pierre angulaire pour récupérer des objets dans les dictionnaires dans O(1)
. C'est cependant très dépendant de votre fonction de hachage résistant aux collisions . Le pire cas pour obtenir un élément dans un dictionnaire est en fait O(n)
.
Sur cette note, les objets mutables ne sont généralement pas hachables. La propriété hashable signifie que vous pouvez utiliser un objet comme clé. Si la valeur de hachage est utilisée comme clé et que le contenu de ce même objet change, alors que devrait retourner la fonction de hachage? Est - ce la même clé ou une autre? Il dépend de la façon dont vous définissez votre fonction de hachage.
Apprendre par exemple:
Imaginez que nous avons cette 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
...
Veuillez noter: tout cela est basé sur l'hypothèse que le SSN ne change jamais pour un individu (Je ne sais même pas où vérifier réellement ce fait à partir d'une source faisant autorité).
Et nous avons Bob:
>>> bob = Person('bob', '1111-222-333', None)
Bob va voir un juge pour changer son nom:
>>> jim = Person('jim bo', '1111-222-333', 'sf bay area')
C'est ce que nous savons:
>>> bob == jim
True
Mais ce sont deux objets différents avec une mémoire différente allouée, tout comme deux objets différents enregistrements de la même personne:
>>> bob is jim
False
Vient maintenant la partie où hash () est pratique:
>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'
Devinez quoi:
>>> dmv_appointments[jim] #?
'tomorrow'
À partir de deux enregistrements différents, vous pouvez accéder aux mêmes informations. Maintenant, essayez ceci:
>>> 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
Ce qui s'est passé? C'est une collision. Parce que {[16] } qui sont les deux entiers btw, nous devons comparer l'entrée de __getitem__
avec tous les éléments qui entrent en collision. Le int
intégré n'a pas d'attribut ssn
donc il se déclenche.
>>> 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>
Dans ce dernier exemple, je montre que même avec une collision, la comparaison est effectuée, les objets ne sont plus égaux, ce qui signifie qu'il soulève avec succès un KeyError
.
Les documents Python pour hash()
État:
Les valeurs de hachage sont des entiers. Ils sont utilisés pour comparer rapidement les clés du dictionnaire lors d'une recherche de dictionnaire.
Les dictionnaires Python sont implémentés en tant que tables de hachage. Donc, chaque fois que vous utilisez un dictionnaire, hash()
est appelé sur les clés que vous passez pour l'affectation, ou la recherche.
De plus, les documents pour l'étatdict
type :
Valeurs qui ne sont pas hashable , c'est-à-dire des valeurs contenant des listes, des dictionnaires ou d'autres types mutables (qui sont comparés par valeur plutôt que par identité d'objet) ne peuvent pas être utilisés comme clés.
Le hachage est utilisé par les dictionnaires et les ensembles pour rechercher rapidement l'objet. Un bon point de départ est L'article de Wikipedia sur les tables de hachage .