为什么嵌套字典可以,但嵌套集禁止?

时间:2015-05-04 22:08:55

标签: python dictionary set hashtable

为什么Python中允许使用嵌套字典,而不允许使用嵌套集?

可以嵌套词典并动态更改子词典,如下所示:

In [1]: dict1 = {'x':{'a':1, 'b':2}, 'y':{'c':3}}
In [2]: dict2 = {'x':{'a':1, 'b':2}, 'y':{'c':3}}
In [3]: dict1 == dict2
Out[3]: True
In [4]: dict2['x'] = {'d':4}
In [5]: dict1 == dict2
Out[5]: False

另一方面,如果你试图在一个集合中放置一个集合,你会收到一个错误,说它无法完成,因为集合是"不可用的类型"

In [6]: set([set(['a'])])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-8e7d044eec15> in <module>()
----> 1 set([set(['a'])])

TypeError: unhashable type: 'set'

但这并不合理,因为字典也是不可用的,

In [7]: hash({'a':1})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-44def9788331> in <module>()
----> 1 hash({'a':1})

TypeError: unhashable type: 'dict' 

当然,可以将一个冷冻集放在一个集合中,

In [8]: set([frozenset(['a'])])
Out[8]: {frozenset({'a'})}

但是之后您无法像嵌套字典那样更改嵌套冻结集的内部。

根据我发现的内容,setdict都是使用哈希表实现的,所以我不明白为什么在一个案例中允许它但不是另一个。

2 个答案:

答案 0 :(得分:8)

问题是你的例子不一样。字典的没有限制,仅限于。这是一个更准确的比较:

>>> d = {{'a': 'b'}: 'c'}

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    d = {{'a': 'b'}: 'c'}
TypeError: unhashable type: 'dict'
>>> s = {{'a': 'b'}, 'c'}

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    s = {{'a': 'b'}, 'c'}
TypeError: unhashable type: 'dict'

请注意,现在您可以获得与预期相同的行为;您可以将set视为仅限密钥dict

您不能将可变/不可用对象用作字典中的键或集合中的元素,因为如果您就地更改它,它将变得不可恢复(Python匹配__eq____hash__这就是为什么必须实现这些方法才能使用自定义类作为键/元素的原因。有关详细信息,请参阅例如Why should dictionary keys be immutable?(不同的语言,但原则相同 - 它都是哈希表)。

如果您对该主题感兴趣,也可以考虑观看The Mighty Dictionary

答案 1 :(得分:2)

由于元素的哈希值在其生命周期内必须是唯一的才能有意义地存储在哈希表中,因此set(以及list)不能成为哈希表的成员正如您所观察到的那样set。但是,在dict中,被散列的对象是,而不是值。因此这是合法的:

{'x': {1, 2, 3}}  #  a string is hashable

而这不是:

{{1, 2, 3}: 'x'}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-1-1cd059738afd> in <module>()
----> 1 {{1, 2, 3}: 'x'}
TypeError: unhashable type: 'set'

对于其他不可用的类型也是如此(例如listdict)。