108 votes

Python, TypeError: type non hachable : 'list'

Je reçois l'erreur suivante dans mon programme. La trace de la pile :

Traceback (most recent call last):
File "C:\Python33\Archive\PythonGrafos\Alpha.py", line 126, in 
menugrafos()
File "C:\Python33\Archive\PythonGrafos\Alpha.py", line 97, in menugrafos
zetta = Beta.caminhografo(grafo,va,vb)
File "C:\Python33\Archive\PythonGrafos\Beta.py", line 129, in caminhografo
if ([vo, a]) in vat == ([vo,vq]) in vat:
TypeError: type non hashable : 'list'

Le programme est censé créer une liste d'adjacence qui fonctionne bien, puis rechercher s'il existe un chemin entre les sommets va et vb. J'ai utilisé un dictionnaire de listes dans collection/defaultdict pour ajouter correctement un sommet adjacent.

Le problème se situe dans les clauses if après la liste a été créée à la fin du programme. Je ne trouve pas de moyen d'utiliser correctement les clauses if avec le dict pour vérifier s'il existe un chemin valide entre les sommets. De plus, grafo est une classe de graphe.

Voici le code :

class graph:
    v = 0
    a = 0
    node = []

class vertex:
    ta = []
    adj = {}

def caminhografo(grafo, va, vb):
    vat = defaultdict(list)
    i = 0
    a = 0
    z = 0
    vo = int(va)
    vq = int(vb)
    vz = int(va)
    vw = int(vb)
    x = len(grafo.node)
    if vz < vw:
        for vz in range (vw+1):
            a = 0
            x = len(grafo.node)
            for a in range (x):
                if [int(vz),int(a)] in grafo.node:
                    vat[vz].append(a)                   
    if vz > vw:
        while vz > vw:
            a = 0
            x = len(grafo.node)
            for a in range (x):
                if[int(va),int(a)] in grafo.node:
                    vat[vz].append(a)
            vz = vz - 1
    a = 0
    x = len(grafo.node)
    print(vat)
    for a in range (x):
       if ([vo, a]) in vat == ([vo,vq]) in vat:
           print("""
    ==============================================
               Existe Caminho
    ==============================================
    """)
           break
       elif ([vo,a]) in vat:
           vo = a
       else:           
           print("""
    ==============================================
             Não Existe Caminho
    ==============================================
        """)
           break

170voto

Brendan Long Points 24372

Le problème est que vous ne pouvez pas utiliser une list comme clé dans un dict, car les clés de dict doivent être immuables. Utilisez plutôt un tuple.

Voici une liste:

[x, y]

Voici un tuple:

(x, y)

Notez que dans la plupart des cas, les ( et ) sont facultatifs, puisque c'est la , qui définit en réalité un tuple (tant qu'il n'est pas entouré de [] ou {}, ou utilisé comme argument de fonction).

Vous pouvez trouver utile la section sur les tuples dans le tutoriel Python:

Bien que les tuples semblent similaires aux listes, ils sont souvent utilisés dans des situations différentes et à des fins différentes. Les tuples sont immuables, et contiennent généralement une séquence hétérogène d'éléments qui sont accessibles via le dépaquetage (voir plus loin dans cette section) ou l'indexation (ou même par attribut en cas de namedtuples). Les listes sont mutables, et leurs éléments sont généralement homogènes et sont accessibles en itérant sur la liste.

Et dans la section sur les dictionnaires:

Contrairement aux séquences, qui sont indexées par une plage de nombres, les dictionnaires sont indexés par des clés, qui peuvent être de n'importe quel type immuable; les chaînes et les nombres peuvent toujours être des clés. Les tuples peuvent être utilisés comme clés s'ils ne contiennent que des chaînes, des nombres, ou des tuples; si un tuple contient un objet mutable soit directement soit indirectement, il ne peut pas être utilisé comme clé. Vous ne pouvez pas utiliser de listes comme clés, puisque les listes peuvent être modifiées en place en utilisant des affectations d'index, des affectations de tranches, ou des méthodes comme append() et extend().


Si vous vous demandez ce que signifie le message d'erreur, c'est parce qu'il n'existe pas de fonction de hachage intégrée pour les listes (par conception), et les dictionnaires sont implémentés comme des tables de hachage.

2voto

not a robot Points 1674

Si vous êtes arrivé sur cette publication parce que vous avez obtenu l'erreur dans le titre, en dehors du problème de OP (où une liste était utilisée comme clé pour un dictionnaire), il existe quelques autres cas où cela peut se produire.

1. Une liste est passée dans un ensemble

Tout comme les listes ne peuvent pas être des clés de dictionnaire, les listes ne peuvent pas être des éléments d'un ensemble. Si un tuple doit y être ajouté, il ne doit pas non plus contenir de liste.

s = {(1, 2), [3, 4]}    # <---- TypeError: type non hashable : 'list'
s = {(1, 2), (3, 4)}    # <---- OK

s.add((5, [6]))         # <---- TypeError parce que l'élément à ajouter contient une liste
s.add((5, 6))           # <---- OK parce que (5, 6) est un tuple
2. Pandas groupby sur des listes

Une autre façon courante de voir cette erreur est si une colonne d'un dataframe pandas stocke une liste et est utilisée comme regroupeur dans une opération de groupby. Une solution similaire à celle ci-dessus consiste à convertir les listes en tuples et à grouper en utilisant la colonne des tuples.

import pandas as pd
df = pd.DataFrame({'group': [[1, 2], [3, 4], [5, 6]], 'value': [0, 1, 2]})

# group  value
# [1, 2]     0
# [3, 4]     1
# [5, 6]     2

df.groupby('group')['value'].mean()                  # <---- TypeError
df.groupby(df['group'].agg(tuple))['value'].mean()   # <---- OK
#          ^^^^^^^^^^^^^^^^^^^^^^  <--- convert each list into a tuple
3. Les étiquettes d'index/de colonne Pandas contiennent une liste

L'étiquette de colonne Pandas ne peut pas être une liste (car c'est analogue à une clé de dictionnaire), donc si vous essayez de la rename() en utilisant une liste, cette erreur s'affichera. La solution est de convertir la liste en tuple (ou même en MultiIndex).

df = pd.DataFrame({'group': range(3)})
df.rename(columns={'group': ['col', 'one']})               # TypeError
df.rename(columns={'group': ('col', 'one')})               # OK
df.columns = pd.MultiIndex.from_tuples([('col', 'one')])   # OK

L'index Pandas peut contenir une liste en tant que valeur mais si vous essayez d'indexer cette ligne, cette erreur sera générée. La solution est de convertir la liste en un tuple ou simplement de "nettoyer" les données (probablement l'index ne doit pas contenir une liste/tuple au départ) comme en le convertissant en MultiIndex.

df = pd.DataFrame({'group': range(3)}, index=[['a'], 'b', 'c'])
df.loc['b']           # TypeError
4. collections.Counter est appelé sur un objet contenant une liste

Parce que Counter crée un objet similaire à un dictionnaire, chaque valeur doit être immutable pour la même raison, donc si un objet contient une liste, cette erreur sera affichée. Une solution consiste probablement à convertir la liste en un tuple

from collections import Counter
lst = ['a', 'b', ['c']]
Counter(lst)                  # TypeError

Counter(['a', 'b', ('c',)])   # OK

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X