为什么嵌套字典可以,但禁止嵌套集?
Why are nested dictionaries OK but nested sets forbidden?
为什么在 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
另一方面,如果您尝试将一个集合放在一个集合中,您会收到一条错误消息,提示无法完成,因为集合是 "unhashable type":
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'
当然可以把frozenset放在一个set里面,
In [8]: set([frozenset(['a'])])
Out[8]: {frozenset({'a'})}
但是您以后不能像对嵌套字典那样更改嵌套 frozenset 的内部结构。
根据我的发现,set
and dict
都是在后台使用哈希表实现的,所以我不明白为什么在一种情况下允许它,而在另一种情况下不允许。
由于元素的散列在其生命周期内必须是唯一的,以便有意义地存储在散列 table 中,set
(以及 list
)可以如您所见,成为 set
的成员。但是,在 dict
中,被散列的对象是 key,而不是值。因此这是合法的:
{'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'
其他不可散列的类型也是如此(例如 list
和 dict
)。
问题是你的例子不一样。字典的 values 没有限制,只有 keys。这是一个更准确的比较:
>>> 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
。
您不能将 mutable/unhashable 对象用作字典中的键或集合中的元素,因为如果就地更改它,它将变得不可恢复(Python 匹配 __eq__
和 __hash__
,这就是为什么必须实现这些方法才能将自定义 class 用作 key/element)。有关更多信息,请参见例如Why should dictionary keys be immutable?(语言不同,原理相同,都是哈希表)
如果您对这个话题感兴趣,您也可以考虑观看 The Mighty Dictionary。
为什么在 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
另一方面,如果您尝试将一个集合放在一个集合中,您会收到一条错误消息,提示无法完成,因为集合是 "unhashable type":
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'
当然可以把frozenset放在一个set里面,
In [8]: set([frozenset(['a'])])
Out[8]: {frozenset({'a'})}
但是您以后不能像对嵌套字典那样更改嵌套 frozenset 的内部结构。
根据我的发现,set
and dict
都是在后台使用哈希表实现的,所以我不明白为什么在一种情况下允许它,而在另一种情况下不允许。
由于元素的散列在其生命周期内必须是唯一的,以便有意义地存储在散列 table 中,set
(以及 list
)可以如您所见,成为 set
的成员。但是,在 dict
中,被散列的对象是 key,而不是值。因此这是合法的:
{'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'
其他不可散列的类型也是如此(例如 list
和 dict
)。
问题是你的例子不一样。字典的 values 没有限制,只有 keys。这是一个更准确的比较:
>>> 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
。
您不能将 mutable/unhashable 对象用作字典中的键或集合中的元素,因为如果就地更改它,它将变得不可恢复(Python 匹配 __eq__
和 __hash__
,这就是为什么必须实现这些方法才能将自定义 class 用作 key/element)。有关更多信息,请参见例如Why should dictionary keys be immutable?(语言不同,原理相同,都是哈希表)
如果您对这个话题感兴趣,您也可以考虑观看 The Mighty Dictionary。