IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

hash- able dict


Sujet :

Python

  1. #1
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut hash- able dict
    Bonjour,

    Quel est le danger à définir hash via id() pour une classe dérivée de dict ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    def __hash__(self): return id(self)
    S'il n'y en pas, pourquoi la classe dict n'est elle pas hashable ?

    Merci d'avance

  2. #2
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    Il me semble pourtant qu'une méthode soit adaptée à ce cas non

    >>> d = {}
    >>> dir(d)
    ['__class__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

  3. #3
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    J'ai peut-être compris votre question qui est plus proche de l'intérêt de la fonction hash() sur un dictionnaire.

    La fonction hash() n'a pas été véritablement prévu pour être utilisé avec les dictionnaires, mais elle permet de déterminer si un objet peut servir comme clé de dictionnaire ou non.

    Un objet ne peut être utilisé comme clé de dictionnaire que si l'objet est hachable.

    Espérant vous avoir aidé

    Edit : On pourrait l'utiliser de cette manière

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> l_1 = ["a", "b", "c"]
    >>> d = {}
    >>> for ind, letter in enumerate(l_1):
    ...     if hash(letter):
    ...         d[letter] = ind
    ...     else:
    ...         raise TypeError
    ... 
    >>> d
    {'a': 0, 'c': 2, 'b': 1}
    Une liste n'étant pas hachable, on peut vérifier qu'une liste ne peut être une clé du dictionnaire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> d = {[12, 5]:"a"}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'

  4. #4
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci Fred,

    Je croyais avoir déjà vu l'erreur "dict is unhashable" en py2.6 (je n'ai pas Python sous la mai, je vérifierai ce soir). Mais la question est la même pour les listes:

    Quel danger à utiliser id(self) comme clef de hashage pour une liste ? Pourquoi n'est-ce pas le comportement par défaut ?

  5. #5
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    Je croyais avoir déjà vu l'erreur "dict is unhashable" en py2.6 (je n'ai pas Python sous la mai, je vérifierai ce soir). Mais la question est la même pour les listes:
    Si vous avez suivi mon raisonnement, cela veut dire qu'un dictionnaire ne peut être une clé d'un dictionnaire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> d = {}
    >>> dic = {d:15, "a":1}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'dict'
    Quel danger à utiliser id(self) comme clef de hashage pour une liste ? Pourquoi n'est-ce pas le comportement par défaut ?
    Tout simplement parce-que id() retourne une identité, et comme chaque objet (liste, dictionnaire, etc...) en ont une, ce ne sera pas une façon de vérifier que cet objet peut être une clé d'un dictionnaire.

  6. #6
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Il doit y avoir une raison technique pour laquelle des structures complexes comme une liste ou un dictionnaire ne sont pas hashables.

    Mais... quel pourrait être l'intérêt pratique d'utiliser un dictionnaire ou une liste comme clé (donc hashée) d'un dictionnaire?

  7. #7
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    En fait tout ce qui est "modifiable" ne peut être une clé de dictionnaire.

    Les tuples "non modifiables" peuvent être une clé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> tup = (12,)
    >>> d = {tup:5}
    >>> d
    {(12,): 5}

  8. #8
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    tout ce qui est "modifiable" ne peut être une clé de dictionnaire.
    Tant que la clef ne dépend pas de ce qui est modifiable (i.e id()), quel est le problème ?

    quel pourrait être l'intérêt pratique
    J'ai rencontré ce problème en codant une classe avec les méthodes suivantes
    *link(self,container) : rajoute self.stock_as() au conteneur, et mémorise le conteneur
    *unlink(self) : retire self de tous les conteneurs qui ont été link().

    Dans link, afin de mémoriser le conteneur, et ce que j'y ai entré, j'ai tenté un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self._linked_to[container]=self.stock_as()
    Pour contourner le problème de non hashable, j'ai finalement opté pour
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self._linked_to[id(container)]=(container,self.stock_as())
    @fred : dsl, je ne comprends pas pourquoi le dictionnaire n'est pas hashable alors qu'il définit __hash__()

    Tout simplement parce-que id() retourne une identité, et comme chaque objet (liste, dictionnaire, etc...) en ont une, ce ne sera pas une façon de vérifier que cet objet peut être une clé d'un dictionnaire.
    Ca ne me convainc pas, sachant que les instances sont usuellement hashables en utilisant justement id (donc pour les instances normales, être hashable et avoir une id() est la même chose!)

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 049
    Par défaut
    Ca ne me convainc pas, sachant que les instances sont usuellement hashables en utilisant justement id (donc pour les instances normales, être hashable et avoir une id() est la même chose!)
    Non, la clé fonctionne avec id() tout simplement parce-que id() renvoie un type int qui lui est hashable.

    @fred : dsl, je ne comprends pas pourquoi le dictionnaire n'est pas hashable alors qu'il définit __hash__()
    La documentation officielle vous persuadera je l'espère

    Citation Envoyé par doc officielle
    Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 697
    Par défaut
    On peut avoir deux dict ou list différentes contenant les mêmes objets.
    De ce fait, les containers mutables ne sont pas hash-ables car l'égalité (du contenu) n'implique pas l'identité (du contenant) - pré-requis à __hash__.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  11. #11
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci Wiztricks,

    Est ce que cela implique, pour rendre hashable une dérivée de dict, qu'il ne me suffit pas de surcharger __hash__, mais qu'il faut aussi surcharger l'égalité (de sorte que l'on compare les id et non le contenu) ?

  12. #12
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Citation Envoyé par VV33D Voir le message
    Est ce que cela implique, pour rendre hashable une dérivée de dict, qu'il ne me suffit pas de surcharger __hash__, mais qu'il faut aussi surcharger l'égalité (de sorte que l'on compare les id et non le contenu) ?
    Techniquement, oui, tu pourrais faire cela: il faut, et il suffit, que deux objets "égaux" (au sens de __eq__) aient le même hash, et que ce hash soit constant. Cela implique que des objets qui possèdent des hash différents, même s'il sont mutables, ne pourront jamais devenir "égaux".

    J'ai du mal à comprendre ce que ça t'apporterait; tu réduis la notion d'égalité à celle d'identité, mais ta solution est valide.

    En pratique, tous les exemples que j'ai vu définissant __hash__ sur des objets mutables étaient toujours foireux...

  13. #13
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 697
    Par défaut
    Citation Envoyé par VV33D Voir le message
    Est ce que cela implique, pour rendre hashable une dérivée de dict, qu'il ne me suffit pas de surcharger __hash__, mais qu'il faut aussi surcharger l'égalité (de sorte que l'on compare les id et non le contenu) ?
    dividee a déjà répondu à la question.

    Les objets "utilisateurs", mutables ou pas, ont par défaut un __hash__ defini à id(self) et un __eq__(self, other) retournant id(self) == id(other).

    Il n'est donc pas si hasardeux de définir une fonction de hash partout!
    Et d'utiliser n'importe quelle instance "utilisateur" (mutable ou pas) comme clé d'un dict...

    Utiliser id comme hash est quelque peu restrictif pour appliquer cela, par défaut, aux dict et aux list. Ca ne serait peut être plus cohérents avec certaines attentes, intuitions.

    Votre s/classe de dict contenant des attributs spécifiques, la comparaison de deux instances sera basée sur la comparaison des "dict"s de la surclasse => il faudra redéfinir l'égalité... et pourquoi pas le hash.
    De fait, si vous n'aviez pas s/classé dict mais crée une classe ayant un dict comme attribut, vous auriez évité ce problème (pour d'autres).
    => l'autre question est de savoir s'il est "raisonnable" d'avoir une s/classe de dict si au bout du compte on le dépoile de ses attributs. Seul vous pouvez y répondre.


    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #14
    Membre Expert
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Par défaut
    Merci beaucoup à vous tous pour ces précisions !

    tu réduis la notion d'égalité à celle d'identité
    Oui. c'est également le cas pour toutes les users-classes qui ne surchargent pas l'égalité. Et ca ne choque en général personne de les mettre dans un set()

    J'ai du mal à comprendre ce que ça t'apporterait
    - J'ai donné un premier exemple: avoir des instances qui savent à quels conteneurs elles appartiennent.
    - Un autre exemple: un jeu vidéo avec des objets, disons des créatures. J'ai besoin de les stocker dans des set(), mais j'ai également besoin qu'elles héritent de dict pour stocker leurs caractéristiques de jeu (force endurance etc).

    Dans ce second exemple, chaque instance de créature est différente des autres, donc réduire l'égalité à l'identité me semble justifié.

    s'il est "raisonnable" d'avoir une s/classe de dict si au bout du compte on le dépoile de ses attributs
    Dans mon cas (2eme exemple ci dessus), j'ai besoin de 2 types d'accès aux attributs d'une instance:
    -creature.attribut me sert a stocker des attributs locaux (non synchronisés par l'envoi de messages réseaux)
    - creature['force']=1 envoie un message réseau pour synchroniser la valeur. Comme wiztricks le suggère, j'aurais tout aussi bien pu faire creature.synchro_data.force=1, mais c'est plus lourd à écrire...

    Encore merci à vous

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [langage] reference et hash complex
    Par mlo dans le forum Langage
    Réponses: 4
    Dernier message: 07/07/2004, 17h46
  2. [langage] hash
    Par giverny dans le forum Langage
    Réponses: 3
    Dernier message: 12/08/2003, 11h27
  3. [langage] probleme avec un hash de hash
    Par planetevoyage dans le forum Langage
    Réponses: 4
    Dernier message: 06/06/2003, 12h55
  4. [langage] Créé un hash dans un fichier...
    Par Smooky dans le forum Langage
    Réponses: 3
    Dernier message: 26/03/2003, 08h49
  5. Tables de hash
    Par miss8 dans le forum C
    Réponses: 2
    Dernier message: 16/11/2002, 17h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo