【问题标题】:Why are mutable user-defined objects hashable, but not lists? [duplicate]为什么可变的用户定义对象是可散列的,而不是列表? [复制]
【发布时间】:2021-03-06 00:19:05
【问题描述】:

用户定义类的实例是可变的,但可散列,即我们可以将它们制成集合或将它们用作dicts 的键。

列表是可变的,但不是可散列的。为什么不呢?

来自Python3 docs 大约 2021 年 3 月 5 日:

作为用户定义类实例的对象可以通过 默认。他们都比较不平等(除了他们自己),他们的 哈希值来自它们的 id()。

为什么不能对列表应用相同的逻辑——即从列表的id() 导出列表的哈希值?不会是列表的id变了吧?

这对什么可以转换为集合或什么可以成为字典中的键有影响。

【问题讨论】:

  • 进一步环顾四周,这在很大程度上与Why mutable built-in objects cannot be hashable in Python? What is the benefit of this? 重叠。我犹豫要不要用我的徽章锤来欺骗它,我会把它留给其他人打电话。
  • 阅读剩下的问题;它询问不可散列的可变内置函数(如list)和可散列的可变用户定义类(默认情况下基于id() 可散列)之间的区别,就像这个问题一样。重点不同,但基本问题非常相似。
  • @user650654 我已将其标记为重复,但无需删除;这里有一个赞成的答案,重复的问题可以让未来的读者更容易通过搜索找到答案。

标签: python python-3.x


【解决方案1】:

您的回答虽然在很大程度上是正确的,但会使事情过于复杂,而且离杂草很远。实际问题的答案(“为什么可变的用户定义对象是可散列的,而不是列表?”)非常简单。 lists 不使用他们的身份作为哈希,因为它需要:

  1. lists 根据身份比较相等性(所以[1, 2, 3] == [1, 2, 3] 总是False,因为它们是不同的lists),或者
  2. lists 将不得不违反哈希不变量,即比较相等的两个对象必须具有相同的哈希(或不可哈希)

因为这两种结果都不可取,list 类会覆盖 __eq__(允许按字典顺序比较 lists),但不能覆盖 __hash__(因为它必须基于内容的哈希值来匹配__eq__ 的实现,但是内容可以改变,所以这样做不安全)。

至于为什么对象默认使用它们的标识,这是有争议的。能够将简单的objects 用作“句柄”有一些小优势,任何对对象有引用的人都可以使用它在dict 中查找。不过,这是一个很小的好处,我怀疑,如果语言是从头开始设计的,__hash__ 默认情况下是未定义的,让类设计人员在适当的时候提供一个理智的__hash__,而不是默默地允许定义的类__eq____hash__ 都不会被散列。

【讨论】:

  • “按字典顺序比较”是什么意思?
  • @martineau:见the Python tutorial section on comparing sequences;基本上,它比较从左(索引 0)到右(索引len(seq) - 1)的内容。对于相等,顺序 mostly 无关紧要(它们要么都相同,要么不相等,但对于无法比较的类型,由于早期元素不相等而提前退出可能会为您节省TypeError),但对于 < 和公司来说,排序很重要,因为结果是基于第一对元素比较不相等的。
  • 感谢您的回答。这两个要求并不明显:为什么要首先按 id 比较列表?您的第二条规则(“比较相等的两个对象必须具有相同的散列”)是不正确的——两个列表(或任何可变的)可以比较为相等但不可散列,即不具有相同的散列。我认为this page 说得更好,但又不明显: hash() 结果应该与相等性一致。相等的对象要么具有相同的散列值,要么被标记为不可散列。
  • @user650654:第二条规则适用于完全有哈希的东西。如果您无法提出保留该不变量的散列解决方案,则不应定义散列。您可以通过多种方式对其进行描述,但不变量仅适用于首先存在哈希的情况。对于“按 id 列出的列表”,这是对您从 id() 派生哈希值的建议的回应;你可以这样做,但为了保持哈希不变,还必须根据 id() 来定义相等性。选项 #1 通过使 list 相等几乎无用来坚持哈希不变量。
  • 我已经删除了我的答案,因为它似乎没有增加价值。
猜你喜欢
  • 2019-03-26
  • 2012-05-02
  • 2023-01-14
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
  • 2019-12-06
  • 2020-03-30
相关资源
最近更新 更多