为什么 dict unioned with dict.keys() return 一个集合?
Why does dict unioned with dict.keys() return a set?
正如我最初预期的那样,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()
return 的并集是 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 的并集,但在其他情况下不允许,为什么在允许的情况下 return 一组键?
字典视图是 "set-like",但与 set
不同,它们没有(类型灵活的)命名方法(如您示例中的 .union
),它们只有保持类型灵活的运算符重载(因为命名方法不存在)。
由于类型灵活,它们使用 any 可迭代作为另一个操作数,并且 dict
s 是它们键的可迭代(list({'a': 1, 'b': 2})
是 ['a', 'b']
),因此在视图操作中将忽略这些值。这并不是说 dict
在这里被特别接受,它们只是像任何其他可迭代对象一样被对待(你可以 |
带有 dict
、list
、[ =19=、range
、生成器或类似文件的对象,它们都可以工作,假设内容可哈希,并生成 set
作为结果。
视图更灵活并不是那么糟糕,因为它们不打算在操作后保留自己的类型,它们应该产生 set
输出。 set
的错位运算符更严格,因为它们不想在确定输出类型时隐式地优先考虑左侧或右侧的类型(它们不希望 set OP nonset
留下任何关于结果是 set
还是 nonset
类型的疑问,并且他们不想让 nonset OP set
有可能表现不同)。由于字典视图无论如何都不保留类型,因此他们决定为其运算符重载采用更自由的设计; view OP nonview
和nonview OP view
的结果是一致的,总是set
.
支持这些特定操作的记录原因是 to match the features of collections.abc.Set
:
For set-like views, all of the operations defined for the abstract base class collections.abc.Set
are available (for example, ==
, <
, or ^
).
和for some reason, collections.abc.Set
doesn't require any of the named methods (aside from isdisjoint
),只有运算符重载。
注意:我不同意这一点(我更希望视图只让他们的操作员与其他视图和 set
/frozenset
一起工作,并且视图有命名方法以及一致性),但现在更改为时已晚,所以它就是这样。
至于 set
方法类型灵活,那更多是一种有意的选择。运算符不会给人一种操作数之一更重要的强烈印象,而方法则必然如此(你调用它的东西显然比参数更重要)。所以这些方法接受任意的可迭代对象(事实上,可以接受多个可迭代对象,如 {1, 2, 3}.union(range(5), range(10, 15))
)和 return 调用它们的对象的类型,而操作符坚持类型一致以避免意外。
正如我最初预期的那样,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()
return 的并集是 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 的并集,但在其他情况下不允许,为什么在允许的情况下 return 一组键?
字典视图是 "set-like",但与 set
不同,它们没有(类型灵活的)命名方法(如您示例中的 .union
),它们只有保持类型灵活的运算符重载(因为命名方法不存在)。
由于类型灵活,它们使用 any 可迭代作为另一个操作数,并且 dict
s 是它们键的可迭代(list({'a': 1, 'b': 2})
是 ['a', 'b']
),因此在视图操作中将忽略这些值。这并不是说 dict
在这里被特别接受,它们只是像任何其他可迭代对象一样被对待(你可以 |
带有 dict
、list
、[ =19=、range
、生成器或类似文件的对象,它们都可以工作,假设内容可哈希,并生成 set
作为结果。
视图更灵活并不是那么糟糕,因为它们不打算在操作后保留自己的类型,它们应该产生 set
输出。 set
的错位运算符更严格,因为它们不想在确定输出类型时隐式地优先考虑左侧或右侧的类型(它们不希望 set OP nonset
留下任何关于结果是 set
还是 nonset
类型的疑问,并且他们不想让 nonset OP set
有可能表现不同)。由于字典视图无论如何都不保留类型,因此他们决定为其运算符重载采用更自由的设计; view OP nonview
和nonview OP view
的结果是一致的,总是set
.
支持这些特定操作的记录原因是 to match the features of collections.abc.Set
:
For set-like views, all of the operations defined for the abstract base class
collections.abc.Set
are available (for example,==
,<
, or^
).
和for some reason, collections.abc.Set
doesn't require any of the named methods (aside from isdisjoint
),只有运算符重载。
注意:我不同意这一点(我更希望视图只让他们的操作员与其他视图和 set
/frozenset
一起工作,并且视图有命名方法以及一致性),但现在更改为时已晚,所以它就是这样。
至于 set
方法类型灵活,那更多是一种有意的选择。运算符不会给人一种操作数之一更重要的强烈印象,而方法则必然如此(你调用它的东西显然比参数更重要)。所以这些方法接受任意的可迭代对象(事实上,可以接受多个可迭代对象,如 {1, 2, 3}.union(range(5), range(10, 15))
)和 return 调用它们的对象的类型,而操作符坚持类型一致以避免意外。