Python's __hash__ function and __eq__ function

Hashed collections require the elements of the collection to achieve a __eq__sum __hash__, and these two methods can be used as a vivid analogy:

A hash set is a lot of buckets, but only one ball can be placed in each bucket.

  • __hash__The function of the function is to find the location of the bucket, which number is the bucket.
  • __eq__The function of the function is that when there is already a ball in the bucket, but another ball comes, it claims that it should also be put into the bucket (the __hash__function tells it the position of the bucket), and the two sides are in a stalemate, then use the __eq__function To judge whether the two balls are equal, if it is judged to be equal, then the ball should not be put into the bucket later, and the hash set maintains the status quo.
class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        print('使用了equal函数的对象的id',id(self))
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False
    def __hash__(self):
        print('f'+str(self.item)+'使用了hash函数')
        return hash(self.item)       
f1 = Foo(1)
f2 = Foo(2)
f3 = Foo(3)
fset = set([f1, f2, f3])
print(fset)
print()
f = Foo(3)
fset.add(f)
print('f3的id:',id(f3))
print('f的id:',id(f))

operation result:

f1使用了hash函数
f2使用了hash函数
f3使用了hash函数
{
    
    <__main__.Foo object at 0x0000023769AB67C0>, <__main__.Foo object at 0x0000023769AC5C10>, <__main__.Foo object at 0x0000023769AC5C40>}

f3使用了hash函数
使用了equal函数的对象的id 2437019360320
f3的id: 2437019360320
f的id: 2437019360368

It can be seen that when f1, f2, and f3 are added to the set, the __hash__function will be called every time .
Since the ___hash__function I defined is return hash(self.item), the position of the bucket found by f and f3 is the same because their items are the same. When executing fset.add(f), f will call its own __hash__function to find the position of the bucket to which f belongs. But this time the bucket has another ball, so you have to spend this time __eq__to determine whether two objects are equal, you can see from the output, is already subject to call __eq__to and subsequent object to be compared (see object id ).
Here, if it is the delete operation fset.remove(Foo(3)), the principle is the same. First use the hash to find the position of the bucket. If there is a ball in the bucket, judge whether the two balls are equal, and if they are equal, put the ball in the bucket Throw it away.

Official explanation

When the hash function is called for the hashable set (set, frozenset, dict), it should return an int value. The only requirement is that if two objects are judged to be equal, then their hash values ​​should also be equal. When comparing two objects for equality, the members of the object are used for comparison. It is recommended to put the members into the original ancestor, and then get the hash value of the original ancestor for comparison.

When the class does not define __eq__()methods, then it should not define __hash__()methods either. If it defines __eq__()methods but not __hash__()methods, then instances of this class cannot be used in hashable collections. If a class defines a mutable object (this should mean that one of the members of the class is a mutable object) and implements a __eq__()method, then this class should not implement the hash() method, because the implementation of hashable objects ( implement) requires that the hash value of the key is unchanged (if the hash value of an object changes, then it will be placed in the wrong hash bucket)

There are defaults __eq__and __hash__methods in user-defined classes ; with it, all object instances are unequal (unless you are comparing yourself with yourself), x == yand are equivalent to this when you compare them hash(x) == hash(y).
Only achieve __eq__(error demonstration)

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Foo:
    def __init__(self, item):
        self.item = item

    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

f1 = Foo(1)
f2 = Foo(1)
f3 = Foo(1)
print(set([f1, f2, f3]))

Run error:

Traceback (most recent call last):
  File "c:/Users/Administrator/Desktop/MyFile/MyCoding/Other/hashtest.py", line 14, in <module>
    print(set([f1, f2, f3]))
TypeError: unhashable type: 'Foo'

Guess you like

Origin blog.csdn.net/sinat_38682860/article/details/109292484