Python >> Tutoriel Python >  >> Python

Méthode magique Python __hash__()

Syntaxe

object.__hash__(x)

Le Python __hash__() la méthode implémente le hash() intégré fonction. Ainsi, lorsque vous appelez le hash(x) , Python tente d'appeler x.__hash__() . Si la valeur de retour n'est pas un entier ou le x.__hash__() méthode n'est pas définie, Python lèvera un TypeError .

Nous appelons cela une "méthode Dunder" pour "D ouble Sous Méthode de score" (également appelée "méthode magique" ). Pour obtenir une liste de toutes les méthodes de dunder avec des explications, consultez notre article sur la feuille de triche de dunder sur ce blog.

Hachage d'arrière-plan()

hash(object) intégré de Python La fonction prend un objet comme argument et renvoie sa valeur de hachage sous forme d'entier. Vous pouvez voir cette valeur de hachage comme une empreinte digitale unique de cet objet.

Comme la valeur de hachage est calculée sur la base des données de l'objet, deux objets différents mais égaux doivent avoir la même valeur de hachage. Il ne s'ensuit pas, cependant, que deux objets avec la même valeur de hachage sont égaux :ils peuvent avoir la même valeur de hachage et être toujours différents.

Exemple personnalisé __hash__()

Dans l'exemple suivant, vous créez une classe personnalisée Data et écrasez le __hash__() méthode magique pour qu'elle renvoie un entier lors de la tentative d'appel de hash(x) sur un Data personnalisé objet.

class Data:
    def __hash__(self):
        return 42


x = Data()
res = hash(x) 

print(res)
# 42

__hash__() par défaut

Si vous ne définissez pas le __hash__() méthode magique, Python renverra sa propre valeur de hachage entière car __hash__() est implémenté pour chaque objet Python.

class Data:
    pass


x = Data()
res = hash(x) 

print(res)
# 42

Ceci est la sortie sur mon ordinateur - ce sera probablement différent sur le vôtre car le résultat représente une adresse mémoire spécifique de l'objet :

116229704442

TypeError :la méthode __hash__ doit renvoyer un entier

Si le Python __hash__ fonction ne renvoie pas de valeur entière, Python lèvera le TypeError: __hash__ method should return an integer en appelant le hash() sur un objet donné. Pour corriger cette erreur, vous devez modifier la valeur de retour de __hash__() à une valeur entière.

Considérez l'extrait de code suivant où vous essayez de renvoyer une chaîne dans la méthode dunder __hash__() :

class Data:
    def __hash__(self):
        return 'finxter'


x = Data()
res = hash(x) 

print(res)

L'exécution de cette opération entraîne le message d'erreur suivant sur mon ordinateur :

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\code.py", line 7, in <module>
    res = hash(x)
TypeError: __hash__ method should return an integer

Bonnes pratiques __hash__

Certaines exigences doivent être satisfaites lors de la mise en œuvre de votre propre __hash__() personnalisé méthode. Je vais les énumérer ici sous forme de liste à puces :

  • La valeur renvoyée doit être un entier.
  • Les objets comparables ont la même valeur de hachage. Donc, si x==y , il devrait s'ensuivre que x.__hash__() == y.__hash__() . Il s'ensuit que si une classe ne définit pas __eq__() pour vérifier l'égalité, il ne doit pas implémenter __hash__() Soit.
  • La valeur de retour de x.__hash__() est tronqué à 4-8 octets lors de l'appel de hash(x) , alors assurez-vous de ne pas perdre accidentellement ces informations. Vous pouvez voir que les sorties diffèrent pour les entiers énormes ici :
class Data:
    def __hash__(self):
        return 99999999999999999999999999999999999999999999999999


x = Data()
res = hash(x) 

print(res)
# 619332571178673745
  • Le __hash__ La méthode sur un objet donné renvoie souvent le résultat de la mise de l'état de l'objet, c'est-à-dire ses valeurs d'attribut, dans un tuple et du hachage du tuple. Voici un exemple :
class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
        
    def __hash__(self):
        return hash((self.name, self.age, self.sex))


ann = Person('Ann', 23, 'w')
ann_2 = Person('Ann', 23, 'w')
alice = Person('Alice', 33, 'w')


print(hash(ann))
print(hash(ann_2))
print(hash(alice))

La sortie montre que les deux premiers objets, bien que différentes instances, produisent la même valeur de hachage :

5084601898576458507
5084601898576458507
-1197787602517711359

Références :

  • https://docs.python.org/3/reference/datamodel.html
  • https://docs.python.org/3.5/reference/datamodel.html#object.__hash__