在dict / set中查找不可哈希对象期间出现“ TypeError:不可哈希类型”

时间:2019-02-22 15:46:03

标签: python hashtable lookup

前言

我了解{/ {1}} / dict / s仅由于其可实现性而应使用可哈希对象创建/更新,因此当此类代码失败时

set

没关系,我已经看到很多此类消息。

但是,如果我想检查>>> {{}} # empty dict of empty dict Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: unhashable type: 'dict' / set中是否有一些不可散列的对象

dict

我也遇到错误

>>> {} in {}  # empty dict not in empty dict

问题

此行为背后的原理是什么?我了解查找和更新可能在逻辑上相连(例如在dict.setdefault method中),但是它不是在修改步骤而不是查找时失败了吗?也许我以某种方式处理了一些可散列的“特殊”值,而另一些(可能是不可散列的)是另一种方式:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'dict'

因此,根据给定的查找行为,我不得不使用其中一个选项

  • LBYL的方式:检查SPECIAL_CASES = frozenset(range(10)) | frozenset(range(100, 200)) ... def process_json(obj): if obj in SPECIAL_CASES: ... # handle special cases else: ... # do something else 是否可哈希,并且仅在此之后检查它是否为obj之一(这不是很好,因为它基于SPECIAL_CASES结构和查找机制的限制,但可以封装在单独的谓词中),
  • EAFP方式:使用某种实用程序进行“安全查找”之类的

    SPECIAL_CASES
  • def safe_contains(dict_or_set, obj): try: return obj in dict_or_set except TypeError: return False / list用于tuple(在查询中不是SPECIAL_CASES)。

还是我错过了一些琐碎的事情?

2 个答案:

答案 0 :(得分:1)

毫无疑问,集和字典在内部运作上非常相似。基本上,概念是您拥有键-值对(或只有一组键),并且键绝不能更改(不变)。如果对象是可变的,则哈希将失去其作为基础数据的唯一标识符的含义。如果您不能确定一个对象是否唯一,则一组唯一键的含义会使它的键唯一性失去作用。这就是为什么可变类型不能作为集合和dict的键使用的原因。以您的示例为例:{} in {} # empty dict not in empty dict我认为您有点误解,因为dict.__contains__仅检查dict的键,而不检查值。由于您永远无法将dict作为键(因为它是可变的),因此无效。

答案 1 :(得分:1)

我在Python错误跟踪器上找到了this issue。长话短说:

如果

>>> set([1,2]) in {frozenset([1,2]): 'a'}

返回False,因为值相等,这在某种程度上是违反直觉的

>>> set([1,2]) == frozenset([1,2])
True

因此,我认为我将在可能发生这种情况的地方编写并使用适当的实用程序。


关于错误的根源:在CPython repo dict___contains__ function(这是dict.__contains__方法的实现中)调用PyObject_Hash function(对应于hash function)- >对于不可散列的对象(例如第一种情况下的{})调用PyObject_HashNotImplemented function->会产生此错误。