何时使用hash()调用__eq__? [英] When does __eq__ gets called using hash()?

查看:83
本文介绍了何时使用hash()调用__eq__?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此处所述,

下面的代码,

class Person(object):
     def __init__(self, name, ssn, address):
         self.name = name
         self.ssn = ssn
         self.address = address
     def __hash__(self):
         print('in hash')
         return hash(self.ssn)
     def __eq__(self, other):
         print('in eq')
         return self.ssn == other.ssn

bob = Person('bob', '1111-222-333', None)

jim = Person('jim bo', '1111-222-333', 'sf bay area')


dmv_appointments = {}
print('calling hash')
dmv_appointments[bob] = 'tomorrow'
print('calling hash')
print(dmv_appointments[jim])
print('calling hash again')
print(dmv_appointments[bob])


输出:


Output:

calling hash
in hash
calling hash
in hash
in eq
tomorrow
calling hash again
in hash
tomorrow


问题:

为什么在访问jim时调用__eq__而不在bob上调用__eq__?

Why __eq__ gets called on accessing jimbut not on bob?

推荐答案

简短答案:字典查找首先进行(廉价)引用相等性检查(x is y )时,只有在该操作失败时才进行(费用更高)相等性检查(x == y).

Short answer: a dictionary lookup first does a (cheap) reference equality check (x is y) when searching a bucket, and only if that fails, a (more expensive) equality check (x == y) is done.

__hash__函数在内部不调用 __eq__.如果构造了bobjim,则不会调用任何此类方法.

The __hash__ function does not call __eq__ internally. Given you construct bob and jim, no such methods are called.

接下来,您bob'tomorrow' 相关联.为了知道字典的哪个存储区,您必须存储bob,您计算哈希值.现在,一旦完成,我们将存储bob(以及值在正确的存储桶中).

Next you associate bob with 'tomorrow'. In order to know in which bucket of the dictionary, you have to store bob, you calculate the hash. Now once you have done that we store bob (and the value in the correct bucket).

接下来,我们要获取jim .为了知道jim存储在哪个存储区中,我们计算哈希值.接下来,我们开始在存储桶中搜索.值区将包含bob.我们先执行参考检查(jim is bob),但是失败了,因此我们回退了平等检查.该检查成功,因此我们返回与bob相对应的值:'tomorrow'.

Next we want to obtain jim. In order to know in which bucket jim resides, we calculate the hash. Next we start searching in the bucket. The bucket will contain bob. We first perform a reference check (jim is bob) but that fails, so then we fallback on the equality check. That check succeeds, so we return the value corresponding with bob: 'tomorrow'.

当我们要查找bob时,会发生相同的情况:我们计算哈希,获取存储桶.在bob is bob上执行参考检查,该检查成功.因此,我们不需要进行(可能更昂贵的相等性检查).我们只需返回值'tomorrow'.

The same scenario happens when we want to look for bob: we calculate the hash, fetch the bucket. Perform a reference check on bob is bob, and that one succeeds. So we do not need a (probably more expensive equality check). We simply return the value 'tomorrow'.

可以先通过以下(不健康的)代码来证明先进行参考检查的事实:

The fact that a reference check is done first can be proven with the following (unhealthy) code:

class Person(object):
     def __init__(self, name, ssn, address):
         self.name = name
         self.ssn = ssn
         self.address = address
     def __hash__(self):
         print('in hash')
         return hash(self.ssn)
     def __eq__(self, other):
         print('in eq')
         return False

在这里,我们始终返回False以获得相等性.甚至:

Here we return always False for equality. So even:

>>> bob == bob
in eq
False
>>> bob is bob
True

bob不等于自身(这实际上不是一个好的设计,因为对于字典来说,一个对象等于其自身是一种契约:良好的平等关系自反对称传递).但是,如果将bob'tomorrow'关联,我们仍然能够获取与bob关联的值:

bob is not equal to itself (this is actually not good design, since for a dictionary, it is a contract that an object is equal to itself: a good equality relation is reflexive, symmetrical and transitive). Nevertheless, if we associate bob with 'tomorrow', we are still able to fetch the value associated with bob:

>>> dmv_appointments = {}
>>> dmv_appointments[bob] = 'tomorrow'
in hash
>>> dmv_appointments[bob]
in hash
'tomorrow'

这篇关于何时使用hash()调用__eq__?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆