Hashable en Python

Le but de cette histoire

dictionnaire

L'un des types intégrés de Python est le dict.

>>> d = {"zero": False, "one": True}
>>> d["zero"]
False
>>> d["one"]
True
>>> type(d)
<class 'dict'>

Les dictionnaires sont des modules sans avoir à les utiliser explicitement dans le programme

>>> type(__builtins__.__dict__)
<class 'dict'>
>>> import os
>>> type(os.__dict__)
<class 'dict'>

Et attributs de classe

>>> class MyClass(object):
...     def __init__(self):
...         self.a = 1
...
>>> x = MyClass()
>>> x.__dict__
{'a': 1}

Il est utilisé implicitement à divers endroits.

Erreur de type lors de l'utilisation d'un dictionnaire

Si vous le spécifiez comme clé de dictionnaire, une erreur peut se produire. Par exemple

>>> a = dict()
>>> type(a)
<class 'dict'>
>>> a[[0]] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Si vous essayez d'utiliser une liste comme clé de dictionnaire comme celle-ci, vous vous fâcherez parce que c'est un type insaisissable. Voyons pourquoi il existe de telles restrictions.

Qu'est-ce que le hachage

https://ja.wikipedia.org/wiki/ハッシュ関数

Fonction de hachage(Fonction de hachage)Ou qu'est-ce qu'une fonction de résumé?
Une opération pour obtenir une valeur numérique représentant les données à partir de certaines données, ou
Une fonction pour obtenir une telle valeur numérique.

La signification de «représenter des données» est que la valeur obtenue par la fonction de hachage est

a == b (a.__eq__(b) == True)Puis hash(a) == hash(b) (a.__hash__() == b.__hash__())

Qu'il rencontre.

Signification de la fonction de hachage dans le dictionnaire

Dans le dictionnaire, les fonctions de hachage sont utilisées pour répondre à la demande de traitement à faible coût, en évitant toute la recherche par `` eq '' lors de la définition et de la récupération des valeurs.

Dans l'implémentation de CPython dict,

Il a été conçu.

Est-il hachable s'il existe une méthode `` hash ''?

__hash__Est-ce hashable tant qu'il y a une méthode? Selon la documentation

http://docs.python.jp/2.7/glossary.html#term-hashable

Un objet hachable a une valeur de hachage qui ne change pas pour le reste de sa vie.(__hash__()Besoin d'une méthode)、...

Et il est nécessaire que la valeur de hachage ne change pas pendant la durée de vie. Cependant, ce n'est généralement pas possible, de sorte que l'implémentation du paramètre de valeur de dictionnaire vérifie uniquement si la fonction de hachage peut être appelée.

La classification des objets intégrés est

Cependant, ce qui est inclus ici dans hashable est garanti que la valeur de hachage ne change pas pendant la durée de vie. Mais qu'en est-il des objets définis par l'utilisateur?

Pour les objets définis par l'utilisateur

clé indéchirable

http://docs.python.jp/2.7/reference/datamodel.html#object.hash

La classe définit des objets modifiables__cmp__()Ou__eq__()Méthode
S'il est mis en œuvre,__hash__()Ne doit pas être défini. Ceci est un hachage dans l'implémentation du dictionnaire
Parce que la valeur doit être immuable.(Lorsque la valeur de hachage de l'objet change
Seau de hachage avec la mauvaise clé:Ce sera dans le seau de hachage)。

Essayons un exemple qui contourne en fait la vérification du type de clé. Dans l'exemple ci-dessous, UnhashableInFact a une fonction de hachage, mais la valeur de hachage change pendant la durée de vie de l'instance.

wrong_bucket.py


# -*- coding: utf-8 -*-
class UnhashableInFact(object):
    def __init__(self, n):
        self.n = n

    def __hash__(self):
        return hash(self.n)

    def __eq__(self, other):
        return self.n == other.n


if __name__ == '__main__':
    a = UnhashableInFact(1)
    b = UnhashableInFact(2)
    mydict = {a: "value for 1", b: "value for 2"}
    print(mydict[a], mydict[b]) # (1)
    a.n = 2                     #→ Changements de valeur de hachage
    print(mydict[a], mydict[b]) # (2)
    c = UnhashableInFact(1)
    print(c in mydict)          # (3)

Quand ceci est exécuté, le comportement est le suivant.

% python wrong_bucket.py
('value for 1', 'value for 2') # (1)Vous pouvez récupérer la valeur de chaque compartiment
('value for 2', 'value for 2') # (2)Tous les deux"value for 2"Va sortir
False                          # (3)Même si vous apportez quelque chose d'égal à la clé d'origine"value for 1"Ne peut pas être retiré

Pourquoi s'est-il comporté ainsi? L'entrée du dictionnaire est

cpython/Include/dictobject.h


typedef struct {
    /* Cached hash code of me_key.  Note that hash codes are C longs.
     * We have to use Py_ssize_t instead because dict_popitem() abuses
     * me_hash to hold a search finger.
     */
    Py_ssize_t me_hash;
    PyObject *me_key;
    PyObject *me_value;
} PyDictEntry;

Il est devenu

Pour déclarer qu'il est insaisissable

http://docs.python.jp/2.7/reference/datamodel.html#object.hash

De la classe des parents__hash__()Hériter de la méthode,__cmp__()Ou__eq__()Sens de
En changeant(Par exemple, passer d'une équivalence basée sur la valeur à une équivalence basée sur l'identité)
Puisque la valeur de hachage de la classe n'est plus valide__hash__ =N'écrire aucun dans la définition de classe
Vous pouvez déclarer explicitement qu'il n'est pas hachable.

Essayons.

unhashable.py


class Unhashable(object):
    __hash__ = None

    def __init__(self, n):
        self.n = n

    def __eq__(self, other):
        return self.n == other.n


if __name__ == '__main__':
    a = Unhashable(1)
    {a: "value for 1"}

De cette façon, vous pouvez le lire lorsque vous l'utilisez comme clé de dictionnaire:

% python unhashable.py
Traceback (most recent call last):
  File "unhashable.py", line 13, in <module>
    {a: "value for 1"}
TypeError: unhashable type: 'Unhashable'

Dans Python3, remplacer `` eq``` le définira automatiquement sur Aucun.

http://docs.python.jp/3/reference/datamodel.html#object.hash

__eq__()Primordial__hash__()Les classes qui ne définissent pas sont implicites
A été défini sur Aucun__hash__()Avoir. classe__hash__()La méthode est
Si aucun, il est approprié d'essayer d'obtenir la valeur de hachage d'une instance de cette classe
TypeError est levé et est une instance(obj, collections.Hashable)vérifier
Ensuite, il sera correctement reconnu comme non hachable.

hashable et immuable

http://docs.python.jp/2.7/glossary.html#term-immutable

Un objet avec une valeur fixe. Les objets immuables incluent des nombres, des chaînes,
Et tuples et ainsi de suite. Les valeurs de ces objets ne peuvent pas être modifiées. Une autre valeur
Vous devez créer un nouvel objet à retenir.
Les objets immuables jouent un rôle important dans les situations où des valeurs de hachage fixes sont requises.
Un exemple est une clé dans un dictionnaire.

Les clés dans les dictionnaires sont mentionnées comme une utilisation d'immuable.

Résumé

Recommended Posts

Hashable en Python
Quadtree en Python --2
Python en optimisation
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
SendKeys en Python
Époque en Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Constante en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Chimie avec Python
DirectLiNGAM en Python
LiNGAM en Python
Aplatir en Python
Aplatir en python
Liste triée en Python
AtCoder # 36 quotidien avec Python
Texte de cluster en Python
AtCoder # 2 tous les jours avec Python
Daily AtCoder # 32 en Python
Daily AtCoder # 6 en Python
Daily AtCoder # 18 en Python
Modifier les polices en Python
Motif singleton en Python
Opérations sur les fichiers en Python
Lire DXF avec python
Daily AtCoder # 53 en Python
Séquence de touches en Python
Utilisez config.ini avec Python
Daily AtCoder # 33 en Python
Résoudre ABC168D en Python
Distribution logistique en Python
AtCoder # 7 tous les jours avec Python
Décomposition LU en Python
GRPC simple en Python
AtCoder # 24 tous les jours avec Python
Résolvez ABC167-D avec Python