TypeError: unhashable type: ‘dict’

Dit stukje code geeft me een foutmelding unhashable type: dictkan iemand me uitleggen wat de oplossing is?

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)

Antwoord 1, autoriteit 100%

Je probeert een dictte gebruiken als sleutel tot een ander dictof in een set. Dat werkt niet omdat de sleutels hashable moeten zijn. Als algemene regel zijn alleen onveranderlijke objecten (strings, integers, floats, frozensets, tupels van onveranderlijke objecten) hashable (hoewel uitzonderingen mogelijk zijn). Dit werkt dus niet:

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

Als je een dictaat als sleutel wilt gebruiken, moet je er iets van maken dat eerst kan worden gehasht. Als het dict dat u als sleutel wilt gebruiken alleen uit onveranderlijke waarden bestaat, kunt u er als volgt een hashbare weergave van maken:

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

Je mag nu keygebruiken als sleutel in een dictof set:

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

Natuurlijk moet je de oefening herhalen wanneer je iets wilt opzoeken met een dictaat:

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

Als het dictdat u als sleutel wilt gebruiken waarden heeft die zelf dictaten en/of lijsten zijn, moet u de toekomstige sleutel recursief “bevriezen”. Hier is een startpunt:

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

Antwoord 2, autoriteit 5%

Een mogelijke oplossing zou kunnen zijn om de JSON dumps() methode te gebruiken, zodat je het woordenboek naar een string kunt converteren —

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

Uitvoer –

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

Other episodes