正如我最初所期望的,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'
这是怎么回事?为什么在某些情况下允许使用字典和集合的并集,而在另一些情况下却不允许,为什么在允许的情况下它返回一组键?
答案 0 :(得分:3)
字典视图是“类似集合的”,但与set
不同,它们没有(类型灵活的)命名方法(如您的示例中的.union
),它们仅具有运算符重载保持类型灵活(因为命名方法不存在)。
类型灵活,它们与 any 可迭代地作为其他操作数一起使用,并且dict
是其键的可迭代项(list({'a': 1, 'b': 2})
是['a', 'b']
),因此在视图操作中将忽略这些值。并不是dict
在这里被特别接受,它们只是像其他可迭代对象一样被对待(您可以|
用dict
,list
,{ {1}},tuple
,生成器或类似文件的对象,它们都可以工作(假定可散列的内容,并产生range
作为结果)。
视图更灵活也很不错,因为它们不打算在操作后保留自己的类型,而是期望它们产生set
输出。 set
的过位运算符更为严格,因为它们在确定输出类型时不希望隐式地优先使用左侧或右侧的类型(它们不希望{ {1}}对结果是set
还是set OP nonset
类型没有任何疑问,他们不想让set
的行为有所不同)。由于字典视图无论如何都不保留类型,因此他们决定为操作符重载使用更宽松的设计。 nonset
和nonset OP set
的结果是一致的,并且始终是view OP nonview
。
支持这些特定操作的记录的原因是to match the features of collections.abc.Set
:
对于类似集合的视图,为抽象基类
collections.abc.Set
定义的所有操作都是可用的(例如nonview OP view
,set
或==
)。
注意:我不同意这一点(我更希望视图仅让其运算符与其他视图以及<
/ ^
一起使用,并且视图具有命名方法。以及为了保持一致性),但现在为时已晚,现在就这样。
对于set
类型灵活的方法,这更多是有意选择。运算符不会给人以强烈的印象,其中一个操作数更重要,而方法则必须这样做(您调用它的东西显然比参数更重要)。因此,这些方法可以接受任意可迭代(并且实际上可以接受多个迭代,例如frozenset
),并返回被调用的对象的类型,而运算符则坚持认为这些类型应避免发生意外。