Hashable, immuable

D'une question récente de SO (voir créer un dictionnaire en python qui est indexé par des listes ) j'ai réalisé que j'avais probablement une mauvaise conception de la signification des objets hashables et immuables en python.

  • que signifie le mot "hashable" dans la pratique?
  • Quelle est la relation entre hashable et immmutable?
  • y a-t-il des objets mutables qui sont des objets hashables ou immuables qui ne sont pas hashable?
71
demandé sur Community 2010-04-20 02:32:07

9 réponses

Hashing est le processus de conversion d'une grande quantité de données en une quantité beaucoup plus petite (généralement un seul entier) d'une manière reproductible de sorte qu'il peut être regardé dans une table en temps constant ( O(1) ), qui est important pour les algorithmes à haute performance et les structures de données.

Immutabilité , c'est l'idée qu'un objet ne changera pas de façon importante après qu'il a été créé, en particulier dans de toute façon qui pourrait changer la valeur de hachage de l'objet.

les deux idées sont liées parce que les objets qui sont utilisés comme clés de hachage doivent typiquement être immuables afin que leur valeur de hachage ne change pas. S'il était permis de changer alors l'emplacement de cet objet dans une structure de données telle qu'un hashtable changerait et alors le but entier de hachage pour l'efficacité est vaincu.

pour vraiment saisir l'idée que vous devriez essayer de mettre en œuvre votre propre hashtable dans un langage comme C/C++, ou lire L'implémentation Java de la classe HashMap .

78
répondu maerics 2010-04-19 22:39:41

Techniquement, hashable signifie que la classe définit __hash__(). Selon les documents:

__hash__() doit retourner un entier. La seule propriété requise est que les objets qui comparent equal ont la même valeur de hachage; il est conseillé de mélanger d'une manière ou d'une autre (par exemple en utilisant exclusive or) les valeurs de hachage pour les composants de l'objet qui jouent également un rôle dans la comparaison des objets.

je pense que pour le python les types builtin, tous les types hashables sont également immuables. Il serait difficile mais pas impossible d'avoir un objet mutable que néanmoins définis __hash__().

7
répondu Andrew Jaffe 2010-04-19 22:46:13
  • y a-t-il des objets mutables qui sont des objets hashables ou immuables qui ne sont pas hashables?

en Python, tuple est immuable, mais il n'est hachable que si tous ses éléments sont hachables.

>>> tt = (1, 2, (30, 40))
>>> hash(tt)
8027212646858338501
>>> tl = (1, 2, [30, 40])
>>> hash(tl)
TypeError: unhashable type: 'list'

Hashable Types

  • atomique immuable types sont tous hashable, comme les str, les octets, les types numériques
  • un ensemble congelé est toujours hashable(ses éléments doivent être hashable par définition)
  • Un n-uplet est hashable seulement si tous ses éléments sont hashable
  • les types définis par L'utilisateur sont hachables par défaut parce que leur valeur de hachage est leur id ()
6
répondu liuyihe 2016-08-07 09:24:36

du Python Glossary :

un objet est hachable s'il a une valeur de hachage qui ne change jamais pendant sa durée de vie (il a besoin d'une méthode __hash__() ), et peut être comparé à d'autres objets (il a besoin d'une méthode __eq__() ou __cmp__() ). Les objets hachables qui comparent equal doivent avoir la même valeur de hachage.

Hashability rend un objet utilisable comme une clé de dictionnaire et un élément de jeu, parce que ces structures de données utilisent la valeur de hachage en interne.

tous les objets intégrés immuables de Python sont hachables, alors qu'aucun conteneur mutable (comme les listes ou les dictionnaires) ne l'est. Les objets qui sont des instances de classes définies par l'utilisateur sont hashables par défaut; ils comparent tous inégal, et leur valeur de hachage est leur id ().

Dicts et les jeux doivent utiliser une table de hachage pour faciliter la recherche dans une table de hachage; les valeurs de hachage doit être immuable, parce que changer le hachage va salir les structures de données et provoquer l'échec du DCT ou du set. La façon la plus simple de rendre la valeur de hachage immuable est de rendre l'objet entier immuable, c'est pourquoi les deux sont souvent mentionnés ensemble.

bien qu'aucun des objets mutables intégrés ne soit hachable, il est possible de faire un objet mutable avec une valeur de hachage qui est pas mutable. Il est courant pour seulement une partie de l'objet de représenter son identité, alors que le reste de l'objet contient des propriétés qui sont libres de changer. Tant que la valeur de hachage et les fonctions de comparaison sont basées sur l'identité mais pas les propriétés mutables, et l'identité ne change jamais, vous avez satisfait les exigences.

5
répondu Mark Ransom 2016-05-09 22:40:28

il y a un implicite même s'il n'y a pas de relation explicite forcée entre immuable et hashable en raison de l'interaction entre

  1. Hashable des objets qui permettent de comparer l'égalité doit avoir la même valeur de hachage
  2. un objet est hachable s'il a une valeur de hachage qui ne change jamais pendant sa durée de vie.

il n'y a pas de problème ici à moins que vous ne redéfinissiez __eq__ de sorte que la classe des objets définit l'équivalence sur la valeur.

une fois que vous avez fait que vous avez besoin de trouver une fonction de hachage stable qui retourne toujours la même valeur pour les objets qui représentent la même valeur (par exemple, où __eq__ ) retourne vrai, et ne change jamais pendant la vie d'un objet.

il est difficile de voir une application lorsque cela est possible, envisager une classe possible A qui satisfait à ces exigences. Bien qu'il y ait le cas dégénéré évident où __hash__ renvoie une constante.

: -

>>> a = A(1)
>>> b = A(1)
>>> c = A(2)
>>> a == b
True
>>> a == c
False
>>> hash(a) == hash(b)
True
>>> a.set_value(c)
>>> a == c
True
>>> assert(hash(a) == hash(c)) # Because a == c => hash(a) == hash(c)
>>> assert(hash(a) == hash(b)) # Because hash(a) and hash(b) have compared equal 
                                 before and the result must stay static over the objects lifetime.

en fait cela signifie à la création hash(b) == hash(c), malgré le fait qu'il n'y a jamais comparable égal. J'ai du mal à voir de toute façon de définir utilement __hash__ () pour un objet mutable qui définit la comparaison en valeur.

Note : __lt__ , __le__ , __gt__ et __ge__ comparsions ne sont pas touchés de sorte que vous pouvez encore définir un ordre d'objets hashables, mutables ou autrement basé sur leur valeur.

4
répondu rgammans 2012-11-05 09:35:36

juste parce que C'est le Top Google hit, voici une façon simple de rendre un objet mutable hashable:

>>> class HashableList(list):
...  instancenumber = 0  # class variable
...  def __init__(self, initial = []):
...   super(HashableList, self).__init__(initial)
...   self.hashvalue = HashableList.instancenumber
...   HashableList.instancenumber += 1
...  def __hash__(self):
...   return self.hashvalue
... 
>>> l = [1,2,3]
>>> m = HashableList(l)
>>> n = HashableList([1,2,3])
>>> m == n
True
>>> a={m:1, n:2}
>>> a[l] = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> m.hashvalue, n.hashvalue
(0, 1)

j'ai en fait trouvé une utilisation pour quelque chose comme cela lors de la création d'une classe pour lancer des enregistrements SQLAlchemy dans quelque chose de mutable et plus utile pour moi, tout en maintenant leur hachabilité pour une utilisation comme clés dict.

3
répondu jcomeau_ictx 2012-06-23 00:28:06

immuable signifie que l'objet ne changera pas de manière significative pendant sa durée de vie. C'est une idée vague mais courante dans les langages de programmation.

Hashability est légèrement différente, et se réfère à la comparaison.

hashable un objet est hashable s'il a une valeur de hachage qui n'a jamais change au cours de sa vie (il a besoin d'une méthode __hash__() ), et peut être comparé à d'autres objets (il nécessite une méthode __eq__() ou __cmp__() ). Les objets hachables qui comparent equal doivent avoir la même valeur de hachage.

toutes les classes définies par l'utilisateur ont la méthode __hash__ , qui par défaut ne renvoie que l'identifiant de l'objet. Ainsi, un objet qui répond aux critères de hachabilité n'est pas nécessairement immuable.

Objets de toute nouvelle classe, vous déclarez peut être utilisé comme une clé de dictionnaire, sauf si vous l'empêchez, par exemple, en lançant de __hash__

on pourrait dire que tous les objets immuables sont hachables, parce que si le hachage change pendant la durée de vie de l'objet, alors cela signifie que l'objet a muté.

mais pas tout à fait. Considérons un tuple qui a une liste (mutable). Certains disent que tuple est immuable, mais en même temps il est quelque peu Non hachable (lancers).

d = dict()
d[ (0,0) ] = 1    #perfectly fine
d[ (0,[0]) ] = 1  #throws

Hashability et l'immuabilité consulter pour objet instancess, pas de type. Par exemple, un objet de type tuple peut être hachable ou non.

3
répondu user2622016 2014-04-15 08:36:13

en Python ils sont la plupart du temps interchangeables; puisque le hash est censé représenter le contenu, il est donc tout aussi mutable que l'objet, et avoir un objet changer la valeur du hash le rendrait inutilisable comme une clé dict.

dans d'autres langues, la valeur de hachage est plus liée à l'identité des objets, et pas (nécessairement) à la valeur. Ainsi, pour un objet mutable, le pointeur peut être utilisé pour démarrer le hachage. En supposant, bien sûr, qu'un objet ne bouge pas en mémoire (comme le font certains GC). C'est l'approche utilisée dans Lua, par exemple. Cela rend un objet mutable utilisable comme clé de table, mais crée plusieurs surprises (désagréables) pour les débutants.

à la fin, avoir un type de séquence immuable (tuples) le rend plus agréable pour les 'touches multi-valeur'.

1
répondu Javier 2010-04-19 22:58:14

Hashable signifie que la valeur d'une variable peut être représentée (ou plutôt encodée) par une constante -- chaîne, Nombre, etc. Or, quelque chose qui est sujet à changement (mutable) ne peut pas être représenté par quelque chose qui ne l'est pas. Par conséquent, toute variable mutable ne peut pas être hachable et, de la même manière, seules les variables immuables peuvent l'être.

Espérons que cette aide ...

0
répondu ktdrv 2010-04-19 22:43:14