Python里hash函數(shù)原理 Python內(nèi)置hash()函數(shù)的實(shí)現(xiàn)機(jī)制解析

hash()函數(shù)用于生成對(duì)象的哈希值,是基于對(duì)象內(nèi)容計(jì)算出的整數(shù),用于快速比較和查找。1.哈希值不是加密,而是整數(shù)標(biāo)識(shí);2.不同對(duì)象可能有相同哈希值,稱為哈希沖突;3.只有不可變對(duì)象如整數(shù)、字符串、元組可被哈希;4.整數(shù)哈希值為其自身,字符串使用siphash算法計(jì)算;5.元組若包含不可哈希元素則不可哈希;6.自定義類需重寫__hash__方法以支持哈希操作;7.hash值不唯一、不穩(wěn)定且依賴環(huán)境設(shè)置。理解哈希機(jī)制有助于提升代碼效率。

python 中的 hash() 函數(shù)看起來簡(jiǎn)單,但背后其實(shí)涉及不少機(jī)制。它不是對(duì)對(duì)象“加密”或“摘要”,而是為對(duì)象生成一個(gè)整數(shù),用來快速判斷對(duì)象是否相等、用于字典和集合這類基于哈希表的數(shù)據(jù)結(jié)構(gòu)中。

什么是 hash 值?

hash() 返回的是一個(gè)整數(shù)值,表示該對(duì)象的“哈希值”。這個(gè)值在對(duì)象生命周期內(nèi)保持不變(前提是對(duì)象不可變),主要用于快速查找和比較。

比如:

>>> hash(10) 10 >>> hash("hello") -9478562939069926921  # 這個(gè)數(shù)字可能每次運(yùn)行都不一樣,取決于 Python 的實(shí)現(xiàn)和環(huán)境

不同對(duì)象可能會(huì)有相同的哈希值,這叫“哈希沖突”,是正?,F(xiàn)象。

立即學(xué)習(xí)Python免費(fèi)學(xué)習(xí)筆記(深入)”;


不同類型對(duì)象的 hash 實(shí)現(xiàn)方式不一樣

Python 中并不是所有對(duì)象都能被 hash()。只有那些不可變的對(duì)象才支持哈希,比如整數(shù)、字符串、元組;而列表、字典這些可變對(duì)象則不能被哈希。

整數(shù)和浮點(diǎn)數(shù)

整數(shù)的哈希值就是它自己:

>>> hash(42) 42

浮點(diǎn)數(shù)的哈希值則稍復(fù)雜,但基本也是映射成一個(gè)固定的整數(shù)。

字符串

字符串的哈希值是根據(jù)內(nèi)容計(jì)算出來的。Python 使用了一種叫做“SipHash”的算法(具體版本可能因 Python 版本和編譯選項(xiàng)而異)來計(jì)算字符串的哈希值。這樣做的目的是為了防止哈希碰撞攻擊。

例如:

>>> hash("abc") -123456789  # 每次運(yùn)行結(jié)果可能不同(Python 啟動(dòng)時(shí)隨機(jī)種子會(huì)影響)

注意:從 Python 3.3 開始,字符串的哈希值會(huì)受 PYTHONHASHSEED 環(huán)境變量影響,這是為了增加安全性。

元組

如果元組中的元素都是可哈希的,那么整個(gè)元組也是可哈希的:

>>> hash((1, 2, 3)) 123456789

但如果元組里包含列表或其他不可哈希對(duì)象,調(diào)用 hash() 會(huì)報(bào)錯(cuò):

>>> hash((1, [2, 3])) TypeError: unhashable type: 'list'

自定義類的 hash 實(shí)現(xiàn)

如果你自定義了一個(gè)類,默認(rèn)情況下它的實(shí)例是可哈希的(因?yàn)槟J(rèn)使用的是對(duì)象的 id)。但如果你重寫了 __eq__ 方法,通常也應(yīng)該同時(shí)重寫 __hash__ 方法,否則你的對(duì)象在放入字典或集合中時(shí)會(huì)出現(xiàn)問題。

舉個(gè)例子:

class Person:     def __init__(self, name):         self.name = name      def __eq__(self, other):         return self.name == other.name      def __hash__(self):         return hash(self.name)

這樣你就可以把 Person 對(duì)象作為字典的鍵或者集合的元素了。


hash() 的局限性與注意事項(xiàng)

  • 不是加密:hash() 并不是為了安全設(shè)計(jì)的,不要用它來做密碼哈希。
  • 值不唯一:不同的對(duì)象可能有相同的 hash 值,這就是哈希沖突。
  • 值不穩(wěn)定:某些類型的 hash 值在每次 Python 啟動(dòng)時(shí)都可能變化(如字符串)。
  • 只適用于不可變對(duì)象:列表、字典這種可變對(duì)象不能被哈希。
  • 環(huán)境依賴:PYTHONHASHSEED 設(shè)置會(huì)影響字符串等類型的哈希值。

基本上就這些。理解 hash 的原理有助于寫出更高效的代碼,尤其是在使用字典、集合或自定義類的時(shí)候。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊11 分享