Python &引用;TypeError:不可损坏类型“;在dict/set中查找不可损坏的对象期间 前言

Python &引用;TypeError:不可损坏类型“;在dict/set中查找不可损坏的对象期间 前言,python,hashtable,lookup,Python,Hashtable,Lookup,我理解dicts/sets应仅因其实现而使用哈希对象创建/更新,因此当此类代码失败时 >>> {{}} # empty dict of empty dict Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: unhashable type: 'dict' 我也会犯错误 Traceback (most recent call last)

我理解
dict
s/
set
s应仅因其实现而使用哈希对象创建/更新,因此当此类代码失败时

>>> {{}}  # empty dict of empty dict
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'dict'
我也会犯错误

Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'dict'
因此,对于给定的查找行为,我不得不使用其中一个选项

  • 方法:检查
    obj
    是否可散列,然后检查它是否是
    特殊情况之一(这不是很好,因为它基于
    特殊情况
    结构和查找机制限制,但可以封装在单独的谓词中)
  • 方法:使用某种实用程序进行“安全查找”,如

  • 使用
    列表
    /
    元组
    处理
    特殊情况
    (在查找时不是
    O(1)

还是我遗漏了一些琐碎的东西?

正如你毫无疑问地意识到的,集合和dict的内部工作原理非常相似。基本上,这个概念是您有键-值对(或者只是有一个集合的键),并且键永远不能更改(不可变)。如果对象是可变的,散列将失去它作为基础数据唯一标识符的意义。如果无法判断对象是否唯一,则一组唯一键的含义会使其唯一性的键属性失效。这就是为什么可变类型在集合中和作为dict的键是不允许的。以您的示例:
{}{}中的空dict而不是空dict中的空dict
我认为您有一点误解,因为
dict.\uuu包含只检查dict的键,而不是值。因为您永远不能将dict作为密钥(因为它是可变的),所以这是无效的。

我在Python bug tracker上找到了它。长话短说:

如果

返回的
False
由于值相等,因此在某种程度上会违反直觉

>>> set([1,2]) == frozenset([1,2])
True
所以我想我会在可能出现这种情况的地方编写并使用适当的实用程序



关于错误的根源:in(这是一个
dict.\uu包含\uu
方法实现)调用(对应于)->对于不可损坏的对象(如第一种情况下的
{}
)调用->生成此错误。

可能重复@quamrana:这篇文章不是关于“如何发现对象是否可哈希”,我知道如何做到这一点,这是关于dict/set查找机制的怪癖。听起来就像python看到:
obj在dict\u或
中,然后它尝试的第一件事是
hash(obj)
。我知道你写的所有东西,
key in dct
检查
key
是否在
dct
中,而不是在值中,我的问题是为什么它会引发
TypeError
,而不是
False
(因为不可损坏的对象不能出现在
dict
keys/
set
元素中)以及通常如何处理case@AzatIbrakov基于这种逻辑,这是否有效<代码>a=[1,2,3];打印(一个[键])
。我在这里看到的问题在静态类型语言中是完全没有意义的,在动态语言中是很常见的。有些操作需要知道类型。我认为这是编程的正常部分,而不是语言错误。@Aaron:moot not mute.@quamrana ty。。我还没有消化早上的咖啡:P
\uuu getitem\uuuuuu
\uuuu contains\uuuuuuuuu
是完全不同的方法,所以我不认为你的例子有什么相关性
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
def safe_contains(dict_or_set, obj):
    try:
        return obj in dict_or_set
    except TypeError:
        return False
>>> set([1,2]) in {frozenset([1,2]): 'a'}
>>> set([1,2]) == frozenset([1,2])
True