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

Nic*_*ger 3 python dictionary hashtable set

为什么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
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

但这也没有意义,因为字典也是不可用的,

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' 
Run Code Online (Sandbox Code Playgroud)

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

In [8]: set([frozenset(['a'])])
Out[8]: {frozenset({'a'})}
Run Code Online (Sandbox Code Playgroud)

但是后来你不能像嵌套字典那样改变嵌套的冻结集的内部结构.

根据我发现的内容,set并且dict都是在引擎盖下使用哈希表实现的,所以我不明白为什么在一个案例中允许它而不是另一个案例.

jon*_*rpe 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'
Run Code Online (Sandbox Code Playgroud)

请注意,现在您可以获得与预期相同的行为; 你可以把它想象set成一个关键的dict.

你不能使用可变/ unhashable对象为一组在字典中的键或元素,因为如果你在原地改变它,它就会变成不可恢复(Python的匹配上__eq____hash__,这就是为什么这些方法必须实现使用自定义class作为键/元素).有关这方面的更多信息,请参阅eg 为什么字典键应该是不可变的?(不同的语言,但相同的原则 - 它是所有哈希表).

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