TypeError: tipo non lavabile: 'dict'


175

Questo pezzo di codice mi sta dando un errore unhashable type: dictqualcuno può spiegarmi qual è la soluzione

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)


3
Sarebbe utile mostrare il rapporto di errore in modo da poter vedere quale riga presenta il problema ...
drevicko,

Risposte:


248

Stai cercando di usare a dictcome chiave per un altro dicto in a set. Non funziona perché le chiavi devono essere hash. Come regola generale, solo gli oggetti immutabili (stringhe, numeri interi, float, frozenset, tuple di immutabili) sono hash (anche se sono possibili eccezioni). Quindi questo non funziona:

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

Per usare un dict come chiave è necessario trasformarlo in qualcosa che potrebbe essere prima cestinato. Se il dict che desideri utilizzare come chiave è costituito solo da valori immutabili, puoi crearne una rappresentazione hash in questo modo:

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

Ora puoi usare keycome chiave in un dicto set:

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

Ovviamente devi ripetere l'esercizio ogni volta che vuoi cercare qualcosa usando un dict:

>>> 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

Se dictsi desidera utilizzare come chiave i valori sono essi stessi dicts e / o elenchi, è necessario "congelare" ricorsivamente la chiave futura. Ecco un punto di partenza:

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

2
Grazie, funziona, tuttavia ottengo ancora errori se il valore è un dict o un elenco (non lavabile), ora sto usando hash (str (my_dict)), funziona bene per me.
Steven Du,

7
solo una nota I dizionari @StevenDu non garantiscono l'ordine, quindi str(my_dict)potrebbero restituire due stringhe diverse per gli stessi (o diversi, ma equivalenti) dicts
K Raphael

1
Per convertire il frozenset risultante in dict, basta chiamare dict(the_frozenset).
utente

4
Mi sembra che frozenset(dict_key.items())sia potenzialmente problematico il fatto che due dicti con lo stesso contenuto ma un ordine di inserimento diverso potrebbero non comportare la stessa chiave. L'aggiunta di una chiamata a sort () sembra in ordine. Ad esempio frozenset(sorted(dict_key.items())), frozenset sembra una scelta strana dato che i set sono esplicitamente non ordinati. Probabilmente funziona bene in pratica, ma la tupla mi sembra una scelta più logica. Sono andato contuple(sorted(dict_key.items()))
Jason Heiss il

Accetto con @JasonHeiss
user3732361

6

Una possibile soluzione potrebbe essere quella di utilizzare il metodo JSON dumps (), quindi è possibile convertire il dizionario in una stringa ---

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

Produzione -

set(['{"a": 10, "b": 20}'])
True

2
Dovrebbe essere dumps, no dump.
Kushan Gunasekera,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.