[Problem background] I customized the Object type. When I used set() to judge the weight, I found that the overload did __eq__
not work. I always thought it was different.
[Cause of the problem] When a custom Object is used as a set () collection element, because the set belongs to the hash algorithm data structure, the hash is first judged when judging the weight, and only when the hash is the same will continue to be called __eq__
to judge the weight. The same is true for other hash data structures.
1. When the magic method is __hash__
called
Please note that this __hash__
magic method:
(1) Called by the built-in function hash()
(2) a set of hash hash type operation member itself: set()
, frozenset([iterable])
,dict(**kwarg)
2 Examples of application scenarios
2.1 Only use __eq__
judgment, no need to overload__hash__
It will only be called when the objects are compared using the parity symbol __eq__
. At this time, the __hash__
correct result can be obtained without overloading :
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Student(object):
def __init__(self, name, age):
self._name = name
self._age = age
def __hash__(self):
print 'Call __hash__'
def __eq__(self, other):
print 'Call __eq__'
if not isinstance(other, Student):
return False
return self._name == other._name and self._age == other._age
if __name__ == '__main__':
s1 = Student('aa', 20)
s2 = Student('aa', 20)
s3 = Student('bb', 21)
print s1 == s2
print s1 == s3
2.2 Comparison strategy of hash structure
In the Python3.X series, if it is only customized __eq__
but not defined __hash__
, then the Object cannot be used as a hash data structure (set, frozenset, dict) element. Because at this time automatically let __hash__
return None;
In the Python2.X series, if it is only customized __eq__
but not defined __hash__
, it can still be used as a hash data structure (set, frozenset, dict) element. At this time, it will cause a BUG in the comparison. The reasons are as follows:
(1) The hash structure first calls the __hash__
comparison Object. The default hash value generation is different (related to the address), so it will always judge that the two Objects are not equal, even if the internal assignments are the same;
(2) When the hash structure is __hash__
equal, the __eq__
comparison will continue to be called .
class Student(object):
def __init__(self, name, age):
self._name = name
self._age = age
def __hash__(self):
print 'Call __hash__'
return hash(self._name + str(self._age)) # 请注意这里一定要返回hash值,否则None报错
def __eq__(self, other):
print 'Call __eq__'
if not isinstance(other, Student):
return False
return self._name == other._name and self._age == other._age
if __name__ == '__main__':
s1 = Student('aa', 20)
s2 = Student('aa', 20)
s3 = Student('bb', 21)
test_set = set()
test_set.add(s1)
print s2 in test_set # True
print s3 in test_set # False