python-3.x 设置操作:应该只适用于集合,但适用于dict_keys?

xuo3flqw  于 2023-03-04  发布在  Python
关注(0)|答案(2)|浏览(117)

集合操作的文档说明:
注意,union()、intersection()、difference()、symmetric_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

所以,这里有一个悖论:

  • 操作符&用于dict_keys对象;
  • 文档中说它应该只适用于集合;
  • dict_keys对象不是集合。

为什么集合运算符&与dict_keys对象一起工作?是否有其他类型可以使用?如何找到这些类型的列表?

iibxawm4

iibxawm41#

这不是完整的答案,但dict_keyscollections.abc.Set的示例:

from collections.abc import Set
k = dict(zip('ac', 'ac')).keys()
print(isinstance(k, Set))  # -> True
nfzehxib

nfzehxib2#

文档的这一部分是关于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异常。
因此,没有悖论,只是数据模型中的一个微妙之处:在X1 M9 N1 X选择退出之后,向X1 M10 N1 X类型提供从右手侧处理二进制运算的机会。

相关问题