Je suis un peu confus sur ce qui peut / ne peut pas être utilisé comme clé pour un dict python.
dicked = {}
dicked[None] = 'foo' # None ok
dicked[(1,3)] = 'baz' # tuple ok
import sys
dicked[sys] = 'bar' # wow, even a module is ok !
dicked[(1,[3])] = 'qux' # oops, not allowed
Donc, un tuple est un type immuable, mais si je cache une liste à l'intérieur, alors ce ne peut pas être une clé ... ne pourrais-je pas aussi facilement cacher une liste à l'intérieur d'un module?
J'avais une vague idée que la clé doit être "hachable" mais je vais juste admettre ma propre ignorance des détails techniques; Je ne sais pas ce qui se passe vraiment ici. Qu'est-ce qui ne va pas si vous essayez d'utiliser des listes comme clés, avec le hachage comme, par exemple, leur emplacement mémoire?
Réponses:
Il y a un bon article sur le sujet dans le wiki Python: Pourquoi les listes ne peuvent pas être des clés de dictionnaire . Comme expliqué ici:
Cela peut être fait sans vraiment enfreindre aucune des exigences, mais cela conduit à un comportement inattendu. Les listes sont généralement traitées comme si leur valeur était dérivée des valeurs de leur contenu, par exemple lors de la vérification de l '(in) égalité. Beaucoup s'attendraient - naturellement - à ce que vous puissiez utiliser n'importe quelle liste
[1, 2]
pour obtenir la même clé, où vous devrez conserver exactement le même objet de liste. Mais la recherche par valeur est interrompue dès qu'une liste utilisée comme clé est modifiée, et pour la recherche par identité, vous devez conserver exactement la même liste - ce qui n'est pas nécessaire pour aucune autre opération de liste commune (du moins aucune à laquelle je puisse penser ).D'autres objets tels que des modules
object
font de toute façon une bien plus grande part de leur identité d'objet (à quand remonte la dernière fois que vous avez appelé deux objets module distinctssys
?), Et sont comparés de toute façon. Par conséquent, il est moins surprenant - ou même attendu - qu'ils, lorsqu'ils sont utilisés comme clés de dict, se comparent également par identité dans ce cas.la source
Pourquoi ne puis-je pas utiliser une liste comme clé dict en python?
(pour quiconque trébuche sur cette question à la recherche d'un moyen de la contourner)
comme expliqué par d'autres ici, en effet vous ne pouvez pas. Vous pouvez cependant utiliser sa représentation sous forme de chaîne à la place si vous souhaitez vraiment utiliser votre liste.
la source
__eq__
. Mais si vous les convertissez en chaînes, tout est comparé par sa représentation sous forme de chaîne.Vous venez de trouver que vous pouvez changer List en tuple, puis l'utiliser comme clés.
la source
Le problème est que les tuples sont immuables et que les listes ne le sont pas. Considérer ce qui suit
Que devrait
d[li]
revenir? Est-ce la même liste? Et pourquoi pasd[[1,2,3]]
? Il a les mêmes valeurs, mais est-ce une liste différente?En fin de compte, il n'y a pas de réponse satisfaisante. Par exemple, si la seule clé qui fonctionne est la clé d'origine, alors si vous n'avez aucune référence à cette clé, vous ne pourrez plus jamais accéder à la valeur. Avec chaque autre clé autorisée, vous pouvez construire une clé sans référence à l'original.
Si mes deux suggestions fonctionnent, alors vous avez des clés très différentes qui renvoient la même valeur, ce qui est plus qu'un peu surprenant. Si seul le contenu d'origine fonctionne, alors votre clé va rapidement mal tourner, car les listes sont faites pour être modifiées.
la source
d[li]
à rester 5.d[[1,2,3]]
ferait référence à un objet de liste différent comme clé, donc ce serait une KeyError. Je ne vois pas encore vraiment de problème ... sauf que laisser une clé récupérer les déchets pourrait rendre certaines des valeurs dict inaccessibles. Mais c'est un problème pratique pas un problème logique ..d[list(li)]
être un KeyError fait partie du problème. Dans presque tous les autres cas d'utilisation ,li
serait indiscernable d'une nouvelle liste avec un contenu identique. Cela fonctionne, mais c'est contre-intuitif pour beaucoup. De plus, à quand remonte la dernière fois que vous devez vraiment utiliser une liste comme clé dict? Le seul cas d'utilisation , je peux imaginer est quand vous êtes tout par l' identité de toute façon hashing, et dans ce cas , vous devriez juste le faire au lieu de compter sur__hash__
et__eq__
d'être fondée sur l' identité.Voici une réponse http://wiki.python.org/moin/DictionaryKeys
La recherche de différentes listes avec le même contenu produirait des résultats différents, même si la comparaison de listes avec le même contenu les indiquerait comme équivalentes.
Qu'en est-il de l'utilisation d'un littéral de liste dans une recherche de dictionnaire?
la source
Étant donné que les listes sont mutables, les
dict
clés (et lesset
membres) doivent être hachables et le hachage d'objets mutables est une mauvaise idée car les valeurs de hachage doivent être calculées sur la base des attributs d'instance.Dans cette réponse, je donnerai quelques exemples concrets, j'espère ajouter de la valeur en plus des réponses existantes. Chaque aperçu s'applique également aux éléments de la
set
structure de données.Exemple 1 : hachage d'un objet mutable où la valeur de hachage est basée sur une caractéristique mutable de l'objet.
Après la mutation
stupid
, il ne peut plus être trouvé dans le dict car le hachage a changé. Seul un balayage linéaire sur la liste des clés du dict est trouvéstupid
.Exemple 2 : ... mais pourquoi pas simplement une valeur de hachage constante?
Ce n'est pas non plus une bonne idée car les objets égaux doivent hacher de manière identique pour que vous puissiez les trouver dans un
dict
ouset
.Exemple 3 : ... ok, qu'en est-il des hachages constants sur toutes les instances?!
Les choses semblent fonctionner comme prévu, mais pensez à ce qui se passe: lorsque toutes les instances de votre classe produisent la même valeur de hachage, vous aurez une collision de hachage chaque fois qu'il y a plus de deux instances en tant que clés dans a
dict
ou présentes dans aset
.Trouver la bonne instance avec
my_dict[key]
oukey in my_dict
(ouitem in my_set
) nécessite d'effectuer autant de contrôles d'égalité qu'il y a d'instances destupidlist3
dans les clés du dict (dans le pire des cas). À ce stade, le but du dictionnaire - la recherche O (1) - est complètement vaincu. Ceci est démontré dans les timings suivants (fait avec IPython).Quelques horaires pour l'exemple 3
Comme vous pouvez le voir, le test d'appartenance à notre
stupidlists_set
est encore plus lent qu'un balayage linéaire sur l'ensemblelists_list
, alors que vous avez le temps de recherche super rapide attendu (facteur 500) dans un ensemble sans beaucoup de collisions de hachage.TL; DR: vous pouvez utiliser
tuple(yourlist)
commedict
clés, car les tuples sont immuables et hachables.la source
x
etz
est le même. Si quelque chose à ce sujet n'est pas clair, veuillez ouvrir une nouvelle question.hash(x)
ethash(z)
.Votre awnser peut être trouvé ici:
Source et plus d'informations: http://wiki.python.org/moin/DictionaryKeys
la source
La réponse simple à votre question est que la liste de classes n'implémente pas la méthode de hachage qui est requise pour tout objet qui souhaite être utilisé comme clé dans un dictionnaire. Cependant, la raison pour laquelle le hash n'est pas implémenté de la même manière que dans la classe de tuple (basée sur le contenu du conteneur) est qu'une liste est modifiable, donc l'édition de la liste nécessiterait le recalcul du hachage, ce qui peut signifier que la liste dans maintenant situé dans le mauvais compartiment dans la table de hachage sous-jacente. Notez que puisque vous ne pouvez pas modifier un tuple (immuable), il ne rencontre pas ce problème.
En remarque, l'implémentation réelle de la recherche de dictobjects est basée sur l'algorithme D de Knuth Vol. 3, Sec. 6.4. Si vous avez ce livre à votre disposition, il pourrait être intéressant de le lire, et si vous êtes vraiment, vraiment intéressé, vous pouvez jeter un coup d'œil aux commentaires des développeurs sur l' implémentation réelle de dictobject ici. Il entre dans les moindres détails quant à son fonctionnement. Il y a aussi une conférence python sur l'implémentation de dictionnaires qui pourrait vous intéresser. Ils passent en revue la définition d'une clé et ce qu'est un hachage dans les premières minutes.
la source
Selon la documentation Python 2.7.2:
Un tuple est immuable dans le sens où vous ne pouvez pas ajouter, supprimer ou remplacer ses éléments, mais les éléments eux-mêmes peuvent être mutables. La valeur de hachage de la liste dépend des valeurs de hachage de ses éléments et change donc lorsque vous modifiez les éléments.
Utiliser des id pour les hachages de liste impliquerait que toutes les listes se comparent différemment, ce qui serait surprenant et peu pratique.
la source
hash = id
ne casse pas l'invariant à la fin du premier paragraphe, la question est de savoir pourquoi ce n'est pas fait de cette façon.quelque chose comme (code psuedo):
Si vous vous demandez quelles sont les options disponibles qui peuvent être utilisées comme clé pour votre dictionnaire. ensuite
Tu peux essayer :
Si cela fonctionne bien, il peut être utilisé comme clé pour votre dictionnaire ou bien le convertir en quelque chose de hachable.
En bref :
tuple(<your list>)
.str(<your list>)
.la source
dict
les clés doivent être hachables. Les listes sont mutables et ne fournissent pas de méthode de hachage valide .la source