集合操作文档说:
注意,union()、intersection()、的非运算符版本 Difference()、 symmetry_difference()、 issubset() 和 issuperset() 方法将接受任何可迭代对象作为参数。相比之下,他们的 基于运算符的对应项需要设置其参数。这 排除像
这样容易出错的结构 更具可读性的set('abc') & 'cbs'
。set('abc').intersection('cbs')
通过以下实验对此进行测试:
# Python 3.10.2 (main, Jan 15 2022, 19:56:27) [GCC 11.1.0] on linux
>>> set('ab') & set('ac')
{'a'}
# works, as expected
>>> set('ab') & 'ac'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'str'
# doesn't work, as expected
>>> set('ab') & list('ac')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'list'
# doesn't work, as expected
>>> set('ab') & iter('ac')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'str_iterator'
# doesn't work, as expected
>>> set('ab') & dict(zip('ac', 'ac')).keys()
{'a'}
# works??
>>> type({}.keys())
<class 'dict_keys'>
>>> isinstance({}.keys(), (set, frozenset))
False
所以,这就是悖论:
set
运算符 &
适用于 dict_keys
对象;dict_keys
对象不是集合。为什么集合运算符
&
可以与 dict_keys 对象一起使用?还有其他类型可以使用吗?我如何找到这些类型的列表?
这不是一个完整的答案,但
dict_keys
是collections.abc.Set
的实例:
from collections.abc import Set
k = dict(zip('ac', 'ac')).keys()
print(isinstance(k, Set)) # -> True
文档的这一部分指的是
set
/frozenset
类型支持的内容。事实上,set
不支持与dict_keys
实例进行比较,并且它正确返回NotImplemented
以指示不支持此操作:
>>> left = set('ab')
>>> right = dict(zip('ac', 'ac')).keys()
>>> left.__and__(right)
NotImplemented
此返回值指示 Python 应尝试与另一个操作数进行“反射操作”,以查看是否受支持。它成功了:
>>> right.__rand__(left)
{'a'}
如果
type(left).__and__
和
type(right).__rand__
都返回NotImplemented
,那么您将看到TypeError
异常。因此,不存在悖论,只是数据模型中的一个微妙之处:在 set
选择退出后,
dict_keys
类型有机会从右侧处理二元运算。集合运算符也可以在 dict_keys 和列表之间工作。 但由于某种原因,集合和列表之间没有,这似乎不一致
Python 3.10.12 (main, Sep 11 2024, 15:47:36) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> s = {1, 2}
>>> d = {2:0, 3:0}
>>> l = [3, 4]
>>> s - d.keys()
{1}
>>> d.keys() - s
{3}
>>> d.keys() - l
{2}
>>> l - d.keys()
{4}
>>> s -l
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'set' and 'list'
>>> l - s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'list' and 'set'