【问题标题】:Why does set() in set() not raise a TypeError, unlike {} in set(), [] in set(), set() in {}, [] in {}, or {} in {}? [duplicate]为什么 set() 中的 set() 不会引发 TypeError,不像 set() 中的 {}、set() 中的 []、{} 中的 set()、{} 中的 [] 或 {} 中的 {}? [复制]
【发布时间】:2020-07-06 16:01:30
【问题描述】:

集合和字典是不可散列的,因此不能包含集合、字典或列表作为键。甚至检查遏制也会引发 TypeError,就像在所有这五种情况下一样:

  • {} in {}
  • [] in {}
  • set() in {}
  • {} in set()
  • [] in set()

但是检查一个集合是否包含一个集合会引发类型错误:

  • set() in set()

返回 False。

为什么set() in set(){} in {}[] in {}set() in {}{} in set()[] in set() 的处理方式不同?

【问题讨论】:

标签: python set


【解决方案1】:

好问题!它似乎没有记录在案,但盯着实现代码似乎是故意的。虽然集合不能包含集合,但它们可以包含frozensets。例如,

>>> s = {frozenset({2, 3}), frozenset({5, 7})}
>>> s
{frozenset({2, 3}), frozenset({5, 7})}
>>> type(s)
<class 'set'>

所以s 包含frozensets,但它本身不是frozenset。现在在这个:

>>> {7, 5} in s
True

set.__contains__() 的实现首先尝试查看{7, 5} 是否在s 中。这会在内部引发TypeError(“key not hashable”)。如果检查键引发类型错误,并且键属于集合类型,则实现清除该错误,从原始键构建临时冻结集,然后重试。

顺便说一句,我不会那样做(太神奇了),但也许有一些我不知道的引人注目的用例。

更正

它已记录在案,但作为 set 文档的最后一行:

注意,__contains__()remove()discard() 方法的 elem 参数可能是一个集合。为了支持搜索等效的 freezeset,从 elem 创建一个临时的。

【讨论】:

  • 在所有这些情况下,另一种可能性是返回False我的集合是否包含这个字典? 很容易回答:不,愚蠢,集合不能包含字典 -> False。毕竟,a == b 也永远不会引发异常,至少对于内置类型不会。但如果这可以追溯到 Python 0.9,我不会感到惊讶。
  • 交叉类型比较在 Python 2 和 3 之间非常不同。除非被覆盖,否则在 Python 3 中交叉类型 == 总是返回 False,交叉类型 @ 987654337@ 总是 True,其他 4 个比较运算符总是引发 TypeError。这是在 Python 2 生命后期首次使用当时新的 datetime 模块类型开创的。在 Python 2 中,除非被覆盖,否则跨类型比较会退回到比较类型的字符串名称;例如,3453345 &lt; "2" 因为"int" &lt; "str"
  • 始终如一地认为dict_keysdict 的行为相同,它们也可以包含frozensets 或将它们作为键。
猜你喜欢
  • 2012-09-14
  • 2016-06-14
  • 2013-12-26
  • 2018-11-21
  • 1970-01-01
  • 2018-10-31
  • 2015-06-18
  • 2015-11-17
  • 1970-01-01
相关资源
最近更新 更多