TypeError: nicht zerlegbar Typ: 'dict'

173

Dieser Code gibt mir einen Fehler. unhashable type: dictKann mir jemand erklären, was die Lösung ist?

negids = movie_reviews.fileids('neg')
def word_feats(words):
    return dict([(word, True) for word in words])

negfeats = [(word_feats(movie_reviews.words(fileids=[f])), 'neg') for f in negids]
stopset = set(stopwords.words('english'))

def stopword_filtered_word_feats(words):
    return dict([(word, True) for word in words if word not in stopset])

result=stopword_filtered_word_feats(negfeats)
user1805250
quelle
3
Es wäre nützlich, den Fehlerbericht
anzuzeigen

Antworten:

247

Sie versuchen, a dictals Schlüssel für ein anderes dictoder in einem zu verwenden set. Das funktioniert nicht, weil die Schlüssel hashbar sein müssen. In der Regel sind nur unveränderliche Objekte (Zeichenfolgen, Ganzzahlen, Gleitkommazahlen, Frozensets, Tupel von unveränderlichen Objekten) hashbar (obwohl Ausnahmen möglich sind). Das funktioniert also nicht:

>>> dict_key = {"a": "b"}
>>> some_dict[dict_key] = True
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

Um ein Diktat als Schlüssel zu verwenden, müssen Sie es in etwas verwandeln, das möglicherweise zuerst gehasht wird. Wenn das Diktat, das Sie als Schlüssel verwenden möchten, nur aus unveränderlichen Werten besteht, können Sie eine hashbare Darstellung davon wie folgt erstellen:

>>> key = frozenset(dict_key.items())

Jetzt können Sie keyals Schlüssel in einem dictoder verwenden set:

>>> some_dict[key] = True
>>> some_dict
{frozenset([('a', 'b')]): True}

Natürlich müssen Sie die Übung wiederholen, wenn Sie etwas mit einem Diktat nachschlagen möchten:

>>> some_dict[dict_key]                     # Doesn't work
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> some_dict[frozenset(dict_key.items())]  # Works
True

Wenn der dictSchlüssel, den Sie als Schlüssel verwenden möchten, Werte und / oder Listen enthält, müssen Sie den potenziellen Schlüssel rekursiv "einfrieren". Hier ist ein Ausgangspunkt:

def freeze(d):
    if isinstance(d, dict):
        return frozenset((key, freeze(value)) for key, value in d.items())
    elif isinstance(d, list):
        return tuple(freeze(value) for value in d)
    return d
Lauritz V. Thaulow
quelle
2
Danke, es funktioniert, aber es wird immer noch ein Fehler angezeigt, wenn der Wert ein Diktat oder eine Liste ist (nicht zerlegbar). Jetzt verwende ich Hash (str (my_dict)). Das funktioniert gut für mich.
Steven Du
7
Nur ein Hinweis @StevenDu-Wörterbücher garantieren keine Reihenfolge und können daher str(my_dict)zwei verschiedene Zeichenfolgen für dieselben (oder unterschiedliche, aber gleichwertige) Wörter zurückgeben
K Raphael
1
Rufen Sie einfach an, um das resultierende Frozenset wieder in Diktat umzuwandeln dict(the_frozenset).
Benutzer
4
Es scheint mir, dass dies frozenset(dict_key.items())möglicherweise problematisch ist, da zwei Diktate mit demselben Inhalt, aber unterschiedlicher Einfügereihenfolge möglicherweise nicht zu demselben Schlüssel führen. Das Hinzufügen eines Aufrufs zu sorted () scheint in Ordnung zu sein. ZB frozenset(sorted(dict_key.items()))Darüber hinaus scheint Frozenset eine seltsame Wahl zu sein, da Mengen explizit ungeordnet sind. In der Praxis funktioniert es wahrscheinlich gut, aber Tupel scheint mir eine logischere Wahl zu sein. Ich ging mittuple(sorted(dict_key.items()))
Jason Heiss
Stimmen
Sie
6

Eine mögliche Lösung könnte darin bestehen, die JSON-Methode dumps () zu verwenden, damit Sie das Wörterbuch in eine Zeichenfolge konvertieren können ---

import json

a={"a":10, "b":20}
b={"b":20, "a":10}
c = [json.dumps(a), json.dumps(b)]


set(c)
json.dumps(a) in c

Ausgabe -

set(['{"a": 10, "b": 20}'])
True
Matteo Boscolo
quelle
2
Es sollte dumpsnicht sein dump.
Kushan Gunasekera