目前,我对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版。你知道吗
要在dict中找到一个键,首先通过散列找到候选键,然后查看它是一个侥幸(即使散列相同,对象也不同)还是您真正想要的键。所以,如果你在散列下找不到任何东西,那就没有什么可以eq的了。你知道吗
想象一下,你在聚会上找熟人,却不知道她是否还在。她有一头红头发。一般来说,你会找红发女孩,然后去面对她们,看看是否真的是她。如果还没有红头发的女孩来,就没有必要检查聚会上的每一个人。(假设你的朋友不喜欢日常染色工作。)
EDIT:CPython将dict存储在一个数组中,其中主数组位置由散列决定;如果该位置被占用,它将以数学上确定的方式跳转到下一个候选位置。由于一个填充的位置可以因此保存“正确的”散列或一个不相关的散列,因此当查找散列时,CPython将从主位置开始,然后继续比较散列,直到它确定不可能存在搜索到的键为止。散列在这里是普通的低级整数,而不是Python对象,这解释了为什么散列比较不会触发
__eq__
。你知道吗注意源代码中的一个可爱的优化:对于每个候选对象,CPython首先检查对象标识;然后才检查哈希是否仍然相同,如果仍然相同,则转到慢检查以查看对象是否相等(使用
PyObject_RichCompareBool
,它最终调用__eq__
)。为什么这很重要?看这里:相关问题 更多 >
编程相关推荐