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í)候。