gpt4 book ai didi

python - 更改 __hash__ 的类仍然适用于字典访问

转载 作者:太空狗 更新时间:2023-10-29 18:31:18 24 4
gpt4 key购买 nike

我所做的显然不是人们想要做的事情,相反,我只是在测试为给定类实现 __hash__

我想看看是否向字典添加一个虚假的“可散列”类,然后更改它的散列值会导致它无法访问它。

我的类(class)是这样的:

class PhonyHash:

def __hash__(self):
val = list("A string")
return id(val) # always different

在我的 IPython 控制台中执行以下操作:

>>> p = PhonyHash()
>>> d = { p: "a value"}
>>> hash(p) # changes hash

然后尝试使用 d[p] 访问元素:

>>> d[p]
"a value"

我明白,这不是应该做的事情,我真的很好奇它为什么有效。 dict 不是使用对象的 hash() 来存储/检索它吗?为什么会这样?

编辑:如@VPfB 的评论所述,sets 出于某种原因按预期运行:

>>> p = PhonyHash()
>>> s = {p}
>>> p in s
False

最佳答案

这是一种奇怪的命运。一些 CPython 机制阻碍了你。三个问题是:

  1. 支持 dict 的数组的初始大小为 8 [1]
  2. CPython 中的所有对象都有以 8 为模的内存地址 [2]
  3. dict 类有一个优化,检查键是同一个对象,如果为真则停止(否则它将根据 __eq__ 方法检查它们是否相等) [3]

这意味着尽管您的对象总是产生不同的散列值,但将检查的后备数组的第一个槽是相同的。如果不是,你会得到一个关键错误,因为插槽是空的。 dict 然后决定它有正确的键,因为它有完全相同的对象,而不仅仅是一个相等的对象。

class PhonyHash:
_hash = 1
def __hash__(self):
return self._hash

p = PhonyHash()
d = {p: "val"}
print(p in d) # True
p._hash = 2
print(p in d) # False
p._hash = 9 # 9 % 8 == 1
print(p in d) # True

CPython 源链接

  1. 字典 struct定义ma_table,以ma_smalltable开头,长度为PyDict_MinSize .
  2. 这记录在 Objects/obmalloc.c
  3. 可以在查找函数中看到herehere

关于python - 更改 __hash__ 的类仍然适用于字典访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38373881/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com