Python內置hash函數爲什麼運行兩次值不一樣

解釋一

python的字符串hash算法並不是直接遍歷字符串每個字符去計算hash,而是會有一個secret prefix和一個secret suffix,可以認爲相當於是給字符串加鹽後做hash,可以規避一些規律輸入的情況

顯然這個secret前後綴的值會直接影響計算結果,而且它有一個啓動時隨機生成的機制,只不過,在2.x版本中,這個機制默認是關閉的,前後綴每次啓動都設置爲0,除非你改了相關環境變量來要求隨機,而在3.x中修改了默認行爲,如果你不配置環境變量,則默認是隨機一個前後綴值,這樣每次啓動都會不同

這個環境變量是PYTHONHASHSEED,無論在2.x還是3.x中,配置爲一個正整數,將作爲隨機種子;配置爲0,則secret前後綴默認清零(和2.x默認行爲就一樣了),配置爲空串或“random”,則表示讓進程隨機生成(和3.x默認行爲一樣)

具體爲啥要這麼做,猜測一個是爲了安全性(防字符串hash表的攻擊,比如php曾經碰到的攻擊),另一個可能也是強調不要依賴一些內建結果,因爲這種算法可能隨着版本而更新,避免有些用戶不看文檔,誤以爲是永遠不變的



作者:冒泡
鏈接:https://www.zhihu.com/question/57526436/answer/153241020
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

 

解釋二

set/dict的hash還真就是這個玩意實現的,因爲它保證了在同一個解釋器進程裏相同字符串hash一致。

因爲CPython 3.x裏的str,它的實體是unicode對象,實體是個utf-8 bytes或者是wstr(嗯這裏真特麼有個『或者』),並且通過一個叫做unicodedata_db的玩意來實現緩存(不然就沒法兒保證str對象的不可變與地址一致性了)。

於是乎當你調內部hash的時候,反正不同進程中的解釋器不會共用一個unicodedata_db,這個解釋器進程裏的字符串的hash到另一個進程裏指不定連個字符串都不是,所以在計算這個內部hash的時候加入了一個code_magic的玩意,同時也均攤了一把複雜度,省得這個db以及set/dict對特定數據表現出極差性能。再說了,誰也不會傻到拿個解釋器內部hash去做跨進程交換。

所以真需要做可重現可跨進程保持一致性的hash,請用hashlib。



作者:Coldwings
鏈接:https://www.zhihu.com/question/57526436/answer/153238652
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章