正如我最初预期的那样,dict
和 set
的联合给出了 TypeError
:
>>> {1:2} | {3}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'dict' and 'set'
然而,令人惊讶的是,
dict
和 dict.keys()
的联合返回了 set
:>>> {1:2} | {3:4}.keys()
{1, 3}
set.union(dict)
也有这种行为:>>> {3}.union({1:2})
{1, 3}
但是
set | dict
没有,并且行为就像 dict | set
:>>> {3} | {1:2}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'dict'
这里发生了什么?为什么在某些情况下允许使用 dict 和 set 的并集,而在其他情况下则不允许,为什么在允许的情况下返回一组键?
最佳答案
字典 View 是“类似设置的”,但与 set
不同,它们没有(类型灵活)命名方法(如您的示例中的 .union
),它们只有操作符重载保持类型灵活(因为命名方法不不存在)。
由于类型灵活,它们可以将任何可迭代对象用作其他操作数,并且 dict
是其键的可迭代对象( list({'a': 1, 'b': 2})
是 ['a', 'b']
),因此在 View 操作中会忽略这些值。并不是说 dict
在这里被特别接受,它们只是被当作任何其他可迭代对象对待(您可以使用 |
、 dict
、 list
、 tuple
、生成器或类文件对象对字典 View 进行 range
工作,假设可散列的内容,并产生一个 set
作为结果)。
更灵活的 View 并不是那么糟糕,因为它们不打算在操作后保留自己的类型,它们应该产生 set
输出。 set
的异地操作符更严格,因为他们不想在确定输出类型时隐式地优先考虑左侧或右侧的类型(他们不希望 set OP nonset
留下任何疑问至于结果是 set
还是 nonset
类型,并且他们不想让 nonset OP set
表现不同)。由于字典 View 无论如何都不会保留类型,因此他们决定对其运算符重载进行更自由的设计; view OP nonview
和 nonview OP view
的结果是一致的,并且始终是 set
。
支持这些特定操作的记录原因是 to match the features of collections.abc.Set
:
和 for some reason, collections.abc.Set
doesn't require any of the named methods (aside from isdisjoint
) ,只有运算符重载。
注意:我不同意这一点(我更希望 View 只让它们的操作符与其他 View 和 set
/frozenset
一起工作,并且 View 还具有命名方法以保持一致性),但为时已晚改变,所以它是这样的。
至于 set
方法是类型灵活的,这更像是一个有意的选择。运算符不会给人一种操作数更重要的强烈印象,而方法则必须这样做(您调用它的东西显然比参数更重要)。因此,这些方法接受任意的可迭代对象(实际上,可以接受多个可迭代对象,如 {1, 2, 3}.union(range(5), range(10, 15))
)并返回它们被调用的对象的类型,而运算符(operator)则坚持类型同意以避免意外。
关于python - 为什么 dict 与 dict.keys() 结合返回一个集合?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55387172/