是什么让一个元素有资格在 Python 中进行集合成员资格测试?

What makes an element eligible for a set membership test in Python?

我想了解哪些项目可以测试 set Python 的会员资格。一般来说,集成员测试的工作方式类似于 Python 中的 list 成员测试。

>>> 1 in {1,2,3}
True
>>> 0 in {1,2,3}
False
>>> 

但是,集合与列表的不同之处在于它们不能包含不可散列的对象,例如嵌套集合。

列表,还行:

>>> [1,2,{1,2}]
[1, 2, {1, 2}]
>>> 

设置,无效,因为不可散列:

>>> {1,2,{1,2}}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> 

现在,即使集合不能是其他集合的成员,我们也可以在成员测试中使用它们。这样的检查不会导致错误。

>>> {1} in {1,2,3}
False
>>> {1,2} in {1,2,3}
False
>>> set() in {1,2,3}
False
>>> 

但是,如果我尝试在被测试的元素是 dict 的情况下进行相同的测试,我会收到一条错误消息,表明被测试的元素不能是不可散列的。

>>> {'a':1} in {1,2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> {} in {1,2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> 

这不是全部,因为 set 可以 测试是否属于另一个集合,即使它本身不可散列,给出结果而不是错误。

所以问题是:是什么让元素符合 Python 中的集合成员资格测试?

混淆是因为当你说 'if set in set' 时,我认为 python 正在将左手集转换为冻结集,然后对其进行测试。例如

>>> f = frozenset({1})
>>> f
frozenset([1])
>>> x = {f, 2, 3}
>>> {1} in x
True

但是,对于字典,没有等同于 frozenset 的方法,因此它无法将字典转换为不可变对象以进行成员资格测试,因此失败。

我不知道这里后面的 'rule' - 是否有一些通用的 方法 可以被覆盖以提供不可变转换,或者这种行为是否是硬编码为 set in set 的特定情况。

您无法测试 set 中不可散列元素的成员资格。例子-

>>> [1,2] in {1,2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> {1:2} in {1,2}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'

唯一可用于包含检查的不可散列对象已设置。正如 documentation -

中给出的

Note, the elem argument to the __contains__(), remove(), and discard() methods may be a set. To support searching for an equivalent frozenset, the elem set is temporarily mutated during the search and then restored. During the search, the elem set should not be read or mutated since it does not have a meaningful value.

为了支持搜索与集合具有相同元素的冻结集,集合暂时变为 frozenset() 并进行比较。例子-

>>> set([1,2]) in {1,2,frozenset([1,2])}
True