我所做的显然不是人们想要做的事情,相反,我只是在测试为给定的类实现__hash__
。在
我想看看如果在字典中添加一个虚假的“hashable”类,然后更改它的哈希值,是否会导致它无法访问它。在
我的班级是这样的:
class PhonyHash:
def __hash__(self):
val = list("A string")
return id(val) # always different
在我的IPython
控制台中执行以下操作:
然后尝试使用d[p]
访问元素会起作用:
>>> d[p]
"a value"
我明白,这不是应该做的事情,我真的很好奇为什么它会起作用。dict
不使用对象的hash()
来存储/检索它吗?为什么这个有用?在
编辑:如@VPfBsets
的评论所述,由于某些原因,其行为符合预期:
>>> p = PhonyHash()
>>> s = {p}
>>> p in s
False
这是一个奇怪的命运。一些CPython的机器阻碍了你。这三个问题是:
dict
的数组的初始大小为8[1]dict
类有一个优化,检查键是否是同一个对象,如果为真则停止在那里(否则它将根据__eq__
方法检查它们是否相等)[3]这意味着,尽管对象总是生成不同的哈希值,但要检查的后备数组的第一个槽是相同的。如果不是,你会得到一个密钥错误,因为插槽是空的。
dict
然后决定它有正确的键,因为它有完全相同的对象,而不仅仅是一个相等的对象。在CPython源的链接
dict
struct定义了ma_table
,它以ma_smalltable
开头,长度为PyDict_MinSize。在我有一个可能的解释:
根据这个来源:http://www.laurentluce.com/posts/python-dictionary-implementation/当保存dict元素的表很小时,只使用哈希的最后几位。在
id()号通常是一个机器地址,很可能与某个内存地址边界对齐。所以最后几位总是零,根本不是随机的。在结果中,您总是命中table[0]元素。在
尝试另一个随机伪哈希源会改变情况,并引发预期的keyror。在
编辑:沙丘用同样的方式回答了这个问题,他比我快。在
相关问题 更多 >
编程相关推荐