作为标题。我的意思是,您可以调用
为什么它们是可哈希的?
next(obj)
并指向下一个元素。因此,可迭代对象或生成器的内部状态会发生更改。为什么它们是可哈希的?
__eq__
,否则对象的相等性由身份定义,并且散列匹配。__eq__
,但没有覆盖了 __hash__
,那么默认情况下会阻止散列(因为影响等式检查结果的可变性将破坏散列不变量);重新启用散列需要实现 __hash__
,其隐含地表示“我的等式和散列语义随时间稳定/一致”,但不要求与等式或散列码无关的内容稳定。__eq__
(在不运行迭代器并且失去刚使用的用于比较的信息的情况下没有有意义的方式来实现它),因此所有基于身份的,就像任何未定义等式的用户定义对象一样。__eq__
的对象以及任何可变但实现了__hash__
的对象作为dict
的键。这是可取的吗? - Marco Sullamynewkey = object()
。由于object()
(像所有没有覆盖__eq__
和__hash__
的对象一样)基于标识进行比较和哈希,所以新创建的object()
必须与所有现有的其他对象不同,并且与稍后可能创建的所有其他对象不同(如果所有对该对象的引用都消失,则可以创建一个新对象,该对象恰好重用内存,但数据存储本身防止对象消失),因此唯一的方法是... - ShadowRanger虽然生成器的内部状态可以改变,但整个生成器在迭代时永远不能添加任何东西,也永远不能退回一步。因此,生成器是一个固定的不可变对象,这几乎就是可哈希性的定义。
但更深层次的是,甚至可变对象只要定义了__hash__
作为实例方法,就可以被散列化,但这对可变对象来说很少是可取的。
__hash__
实现将忽略可变对象的可变部分。 - chepner__hash__
的事实是该对象不可变的必要但不充分条件? - Marco Sulla__hash__
方法。 - juanpa.arrivillaga__hash__
,不可变的定义不同,它是一个不能“原地”更改并且对其进行的任何更改都必须替换它的对象。迭代生成器并不会改变生成器,它只是逐个读取它。 - Ofer Sadan
x = itertools.count(5)
为例。如果你调用next(x)
,它将修改x
的内部状态并返回 5。但是,下一次调用next(x)
,你就知道它会返回 6;没有任何方法可以改变x
本身来改变这个结果。从这个意义上说,x
是不可变的。 - chepnercount(5)
是可哈希的,因为它的哈希值不依赖于迭代器的当前状态;无论next(x)
返回6、19或其他什么值,都不能改变count(5)
表示以5开始的无限整数序列的事实。相比之下,list
的一个实例除了其当前内容外没有唯一的标识(因此也没有哈希值),因为对于任何两个列表x
和y
,你都可以通过一系列的pop
和append
调用使它们等价。 - chepner