Python 中的hash
【問題背景】我自定義了Object類型,在用set()進行判重的時候發現重載了__eq__不起作用,總是認為不同的。
【問題原因】當自定義的Object作為set()集合元素時,由于set 屬于哈希算法數據結構,因此判重時首先會判斷hash,只有當hash相同時才會繼續調用__eq__來判重。其他哈希數據結構也如此。
1 .魔法方法__hash__調用時機
請注意這個 __hash__魔法方法:
(1)被內置函數hash()調用
(2)hash類型的集合對自身成員的hash操作:set(), frozenset([iterable]), dict(**kwarg)
2 應用場景舉例
2.1 僅用到__eq__判等,無需重載__hash__
當Object間使用判等符號來比對時僅會調用__eq__,這個時候不需要重載__hash__就能得到正確結果:
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Student(object):def __init__(self, name, age):self._name = nameself._age = agedef __hash__(self):print 'Call __hash__'def __eq__(self, other):print 'Call __eq__'if not isinstance(other, Student):return Falsereturn self._name == other._name and self._age == other._ageif __name__ == '__main__':s1 = Student('aa', 20)s2 = Student('aa', 20)s3 = Student('bb', 21)print s1 == s2print s1 == s32.2 哈希結構體的比對策略
在Python3.X系列版本中,如果僅自定義__eq__而沒有定義__hash__,那么該Object無法作為哈希數據結構(set、frozenset、dict)元素。因為此時自動讓__hash__返回None;
在Python2.X系列版本中,如果僅自定義__eq__而沒有定義__hash__,那么仍然可以作為哈希數據結構(set、frozenset、dict)元素,此時會導致比對存在BUG,原因如下:
(1)哈希結構體首先調用__hash__比對Object,默認的哈希值生成是不一樣的(與地址有關),因此總會判斷兩個Object不相等,哪怕內部賦值都一樣也不行;
(2)哈希結構體在__hash__相等的情況下,會繼續調用__eq__比對。
class Student(object):def __init__(self, name, age):self._name = nameself._age = agedef __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 Falsereturn self._name == other._name and self._age == other._ageif __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 # Trueprint s3 in test_set # False總結
以上是生活随笔為你收集整理的Python 中的hash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python两种生成md5的方法
- 下一篇: python实用小方法