类型错误:不可散列的类型:'dict'
- 2025-01-16 08:38:00
- admin 原创
- 109
问题描述:
这段代码给了我一个错误
TypeError: unhashable type: dict
谁能向我解释一下解决方案是什么?
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)
解决方案 1:
您尝试将 a 用作另一个或 a 中的dict
键。这行不通,因为键必须是可哈希的。一般来说,只有不可变对象(字符串、整数、浮点数、冻结集、不可变元组)才是可哈希的(尽管可能存在例外)。所以这行不通:dict
`set`
>>> dict_key = {"a": "b"}
>>> some_dict[dict_key] = True
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
要将字典用作键,您需要先将其转换为可以散列的内容。如果您希望用作键的字典仅由不可变值组成,则可以像这样创建它的可散列表示:
>>> key = frozenset(dict_key.items())
现在您可以在 a或中使用它key
作为键:dict
`set`
>>> some_dict[key] = True
>>> some_dict
{frozenset([('a', 'b')]): True}
当然,每当你想使用字典查找某些内容时,你需要重复这个练习:
>>> 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
如果dict
您希望用作键的键值本身是字典和/或列表,则需要递归地“冻结”预期键。这是一个起点:
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:
一种可能的解决方案可能是使用 JSON dumps() 方法,这样您就可以将字典转换为字符串 ---
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
输出 -
set(['{"a": 10, "b": 20}'])
True
解决方案 3:
发生这种情况是因为我在用 Typescript 思考,并尝试设置如下 python 字典:
thing = { 'key': 'value' }
other_thing = {'other_key': 'other_value'}
my_dictionary = { thing, other_thing }
然后我尝试:
my_dictionary = { thing: thing, other_thing: other_thing }
...仍然没有效果
最终起作用的是......
my_dictionary = { 'thing': thing, 'other_thing': other_thing }
有趣的是,我们如何习惯不同语言的小语法技巧......
解决方案 4:
如果您尝试将一个字典用作另一个字典的键(例如{{}: 1}
),或者将一个字典添加到集合(例如{{}}
),或者检查 set/dict_keys 中是否存在字典(例如{} in set()
),或者使用一列字典作为 pandas groupby 中的分组器,就会发生此错误。
可能的解决方案:
1. dict.items()
->tuple
如果字典的插入顺序很重要(如果转换为冻结集,则会丢失),则重构代码以将用作字典键/添加到集合中的字典转换为元组。例如,OP 中的问题是尝试使用字典(从word_feats
函数返回)作为另一个字典的键。例如,
# dict as key of another dict
d1 = {'a': 1, 'b': 2}
d2 = {d1: 3} # <--- TypeError: unhashable type: 'dict'
d2 = {tuple(d1.items()): 3} # <--- OK
# dicts in a set
st = {d1, d2} # <--- TypeError: unhashable type: 'dict'
st = {tuple(x.items()) for x in (d1, d2)} # <--- OK
# membership tests
d1 in d2 # <--- TypeError: unhashable type: 'dict'
tuple(d1.items()) in d2 # True
因此,对于 OP 中的示例,返回 a 而不是 可以dict
解决tuple
问题。
def word_feats(words):
return dict([(word, True) for word in words]) # <--- TypeError
def word_feats(words):
return tuple((word, True) for word in words) # <--- OK
如果您尝试使用@functools.lru_cache()
装饰器缓存从函数返回的字典并收到此错误,则此解决方案很有用。重构函数以返回元组可解决此错误。
2 dict
.->str
另一种方法是简单地将字典转换为字符串。与 类似tuple()
,它保留了插入顺序。然后,如果需要将字符串化的键转换回字典,ast.literal_eval()
可以使用标准库来恢复它。
import ast
d1 = {'a': 1, 'b': 2}
d2 = {str(d1): 3} # {"{'a': 1, 'b': 2}": 3}
str(d1) in d2 # True
[ast.literal_eval(key) for key in d2.keys()] # [{'a': 1, 'b': 2}]
3. dict.items()
->frozenset
由于冻结集不保留顺序,因此如果你想将字典添加到集合中,比如在列表中查找唯一字典,那么这种方法就很理想。然后,要从冻结集中恢复原始字典,请调用dict()
每个冻结集。例如,
lst = [{1:3, 2:0}, {2:0, 1:3}, {2:3}] # list of dicts
set(lst) # <--- TypeError: unhashable type: 'dict'
st = {frozenset(d.items()) for d in lst} # convert each dict into a frozenset
# convert back into a list of unique dicts
[dict(d) for d in st] # [{2: 3}, {2: 0, 1: 3}]
正如上面最后一行代码的输出所示,lst[0]
和中只有一个lst[1]
被正确保留,因为lst[0]==lst[1]
为 True。
4 dict
.->json.dumps()
如果字典是 json 可序列化的,那么转换为 json 对象也可用于在列表中查找唯一字典。如果要确保键的顺序无关紧要,请使用sort_keys=
的参数json.dumps()
。但是,需要注意的一件重要事情是 json 要求键是字符串,因此如果键是数字(如下所示),则在存在非字符串键的情况下,转换为 json 并转换回字典可能无法恢复原始字典。
import json
lst1 = [{1:3, 2:0}, {2:0, 1:3}]
[json.loads(j) for j in {json.dumps(d, sort_keys=True) for d in lst1}]
# [{'1': 3, '2': 0}]
解决方案 5:
要获得一组字典(由于字典是可变的,所以无法创建),我建议您改用字典的字典。然后您可以将其与@StevenDu 的建议结合起来
mydict: Dict[int, dict] = {}
d1 = {'a': 1, 'b': 2}
mydict[hash(str(d1))] = d1
请注意,您可以使用任何自定义方式(而不是“hash(str(d1))”来获取字典的唯一键。
解决方案 6:
使用嵌套函数将嵌套字典中的字典转换为元组。
def make_hashable(d: dict[str, Any]) -> tuple:
"""Convert a dictionary, which is un-hashable into a tuple which is a hashable form."""
return tuple(
sorted(
(k, make_hashable(v)) if isinstance(v, dict) else (k, v)
for k, v in d.items()
)
)
解决方案 7:
def frozendict(d: dict):
keys = sorted(d.keys())
return tuple((k, d[k]) for k in keys)
实现上述函数返回一个不可变的结构,我们更喜欢对键进行排序以防止无序迭代。
解决方案 8:
有一个很好的包叫frozendict
pip3 install frozendict
from frozendict import frozendict
然后要么
d = frozendict(role="user", content=prompt)
或者
d = frozendict(my_dict)