TypeError: unhashable type: 'dict'


175

Este pedaço de código está me dando um erro. unhashable type: dictAlguém pode me explicar qual é a solução

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
Seria útil para mostrar o relatório de erro para que possamos ver qual linha tem o problema ...
drevicko

Respostas:


248

Você está tentando usar um dictcomo uma chave para outro dictou em um set. Isso não funciona porque as chaves precisam ser laváveis. Como regra geral, apenas objetos imutáveis ​​(seqüências de caracteres, números inteiros, flutuadores, conjuntos de propriedades, tuplas de imutáveis) são laváveis ​​(embora sejam possíveis exceções). Portanto, isso não funciona:

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

Para usar um ditado como chave, você precisa transformá-lo em algo que pode ser primeiro misturado. Se o ditado que você deseja usar como chave consistir apenas em valores imutáveis, você poderá criar uma representação hashável assim:

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

Agora você pode usar keycomo chave em um dictou set:

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

Claro que você precisa repetir o exercício sempre que quiser procurar algo usando um ditado:

>>> 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 dictvocê deseja usar como chave possui valores que são dictos e / ou listas, é necessário "congelar" recursivamente a chave em potencial. Aqui está um ponto de partida:

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
Obrigado, funciona, porém ainda recebo erro se o valor for um dict ou list (unhashable), agora estou usando hash (str (my_dict)), funciona bem para mim.
Steven Du

7
apenas dicionários uma nota @StevenDu não garantir a ordem, para que str(my_dict)pudesse voltar duas cordas diferentes para os mesmos (ou diferentes, mas equivalentes) dicts
K Raphael

1
Para converter o frozenset resultante em ditado, basta ligar dict(the_frozenset).
usuário

4
Parece-me que frozenset(dict_key.items())é potencialmente problemático, pois dois ditados com o mesmo conteúdo, mas com ordem de inserção diferente, podem não resultar na mesma chave. Adicionar uma chamada a classificado () parece em ordem. Por exemplo: frozenset(sorted(dict_key.items()))Além disso, o frozenset parece uma escolha estranha, uma vez que os conjuntos são explicitamente desordenados. Provavelmente funciona bem na prática, mas a tupla parece uma escolha mais lógica para mim. Eu fui comtuple(sorted(dict_key.items()))
Jason Heiss

Concordo com @JasonHeiss
user3732361 19/02

6

Uma solução possível pode ser usar o método JSON dumps (), para que você possa converter o dicionário em uma sequência ---

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

Resultado -

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

2
Deveria ser dumps, não dump.
Kushan Gunasekera
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.