Python:如果key不在dictionary中,为什么不调用uuueq_uuuuu()?

2024-03-28 09:51:00 发布

您现在位置:Python中文网/ 问答频道 /正文

目前,我对Python的内置类型做了一些研究。我不知道调用什么方法来检查键是否在字典中。例如,如果我检查int类型的键是否在字典中,那么__eq__()方法仅在字典.keys()包含它。如果不是__eq__(),则不调用。你知道吗

下面是一个代码示例:

dict = {
  1: "Hello",
  2: "World", 
  4: "Foo"
}

assert 1 in dict.keys() # the __eq__() method of int is invoked
assert not(3 in dict.keys()) # no __eq__() method of int is invoked

我知道,字典包含一个哈希(key)、key和value的元组。但是我有点困惑,为什么在第二个断言中没有调用__eq__()。你知道吗

为了测试这个行为,我从int继承并设置了一些断点。以下是我的自定义int类的摘录:

tint(int):
    def __new__(cls, value, *args, **kw):
        return super(tint, cls).__new__(cls, value)

    def __init__(self, value):
        super().__init__()

    def __eq__(self, other):
        return super().__eq__(other) # with breakpoints

    def __ne__(self, other):
        return super().__ne__(other) # with breakpoints

    def __hash__(self):
        return tint(super().__hash__()) # with breakpoints

我在Ubuntu 18.04.1 LTS上使用Python 3.6.5版。你知道吗


Tags: selfreturn字典valuedefwithkeysdict
1条回答
网友
1楼 · 发布于 2024-03-28 09:51:00

要在dict中找到一个键,首先通过散列找到候选键,然后查看它是一个侥幸(即使散列相同,对象也不同)还是您真正想要的键。所以,如果你在散列下找不到任何东西,那就没有什么可以eq的了。你知道吗

想象一下,你在聚会上找熟人,却不知道她是否还在。她有一头红头发。一般来说,你会找红发女孩,然后去面对她们,看看是否真的是她。如果还没有红头发的女孩来,就没有必要检查聚会上的每一个人。(假设你的朋友不喜欢日常染色工作。)

EDIT:CPython将dict存储在一个数组中,其中主数组位置由散列决定;如果该位置被占用,它将以数学上确定的方式跳转到下一个候选位置。由于一个填充的位置可以因此保存“正确的”散列或一个不相关的散列,因此当查找散列时,CPython将从主位置开始,然后继续比较散列,直到它确定不可能存在搜索到的键为止。散列在这里是普通的低级整数,而不是Python对象,这解释了为什么散列比较不会触发__eq__。你知道吗

注意源代码中的一个可爱的优化:对于每个候选对象,CPython首先检查对象标识;然后才检查哈希是否仍然相同,如果仍然相同,则转到慢检查以查看对象是否相等(使用PyObject_RichCompareBool,它最终调用__eq__)。为什么这很重要?看这里:

class Foo:
    def __eq__(self, other):
        return False             # This shouldn't match...
    def __hash__(self):
        return 7

f = Foo()
d = { f: "Yes!" }
print(d[f])                      # ...and yet it does! :)
# => "Yes!"

相关问题 更多 >