2011-03-27 74 views
4

爲什麼None哈希-1042159082(我發現等於字節數在技嘉否定)?Python的 - 大約哈希和問題`None`

我知道這並沒有真正影響我的代碼,但我很好奇。

哈希值是用於字典鍵查找窗口,所以我決定嘗試:

>>> D = {-1042159082: 'Hello', None: 'Hi'} 
>>> D[None] 
'Hi' 
>>> D[-1042159082] 
'Hello' 
>>> 

我明白這是Python的看到兩個相同的哈希值,然後檢查類型,看看什麼是什麼。是對的嗎?

>>> {False: 'Hello', 0: 'Hi'} 
{False: 'Hi'} 
>>> {0: 'Hi', False: 'Hello'} 
{0: 'Hello'} 

這很奇怪。更重要的是,第一個鍵被保留,第二個值被保留。

這是巫術,或者可能有人幫助我明白了嗎?

回答

6

關於傳遞給內置hash()功能(None-1042159082在問問題)時可能產生相同的輸出2倍的值:

這就是所謂的碰撞(參見維基百科this頁更多關於碰撞的信息)。

Python使用的散列算法有一個特殊的方法來確定當發生衝突時人們真正想要的值(請參閱從第51行開始的CPython源代碼(主Python解釋器)中的this頁面)在寫這個答案的時候獲得關於碰撞的信息; this文件也有關於如何實現dicts的註釋)。

關於0False(以及更有用的信息)會發生什麼,請參閱當前問題的其他答案。

+0

這一切都是真實的,但請記住,在OP的示例中不存在哈希碰撞:它是* same *鍵值。在Python中,False等於整數0. – 2011-03-27 06:38:45

+0

Ned Deily:謝謝,澄清了答案即將回答的關於碰撞的答案部分。 – Abbafei 2011-03-27 06:48:17

+0

@Ned - 你說錯了。 'None'散列到被重用爲另一個鍵的同一個負整數,但兩個鍵都保留在字典中。這與'False':'0'例子不一致,其中相同的行爲導致了不同的結果。 @阿不菲,謝謝你的正確答案。我研究了源代碼C,看到與'Py_None'有關的條件是非常有趣的。 – orokusaki 2011-03-27 18:22:48

2

沒有,即使兩個對象碰巧具有相同的哈希,他們仍然不會導致鍵衝突。 Python檢測這個並且解決它(儘管請不要問我如何)。

False相同0True是一樣的1,所以當你無論是在一個字典建設使用,你使用相同的密鑰將另一項目時更新值。

3

你不能和不應該依賴於對Python對象特定的哈希值。它是實現和機器相關的。在我的機器:

>>> hash(None) 
268532216 

至於填充dict對象去(沒有hash對象在Python),也許下面將幫助:

>>> False == 0 
True 
>>> {0: 'Hello', 0: 'Hi'} 
{0: 'Hi'} 
>>> {0: 'Hi', 0: 'Hello'} 
{0: 'Hello'} 
>>> {False: 'Hello', False: 'Hi'} 
{False: 'Hi'} 
>>> {False: 'Hi', False: 'Hello'} 
{False: 'Hello'} 

當使用dict構造函數時,提供兩個key=value對,但它們都具有相同的密鑰(即可哈希值),因此,由於字典中的鍵值必須是唯一的,最後一個值是保存的值。換句話說,每一個構造函數上面創建一個項目字典的:

>>> print {False: 'Hello', 0: 'Hi'} 
{False: 'Hi'} 

更多信息,請參見here

0

你如何看待沒有哈希值?

>>> d = {None:'hi'} 
>>> d.get(-1042159082) 
>>> d.get(None) 
'hi' 
>>> 
>>> hash(None) 
268532214 
>>> 

我不會依賴散列的值無,永遠。

至於使用文字的字典解析,我假設在內部定義一個'等於'另一個的關鍵,只是做一個更新而不是直接添加。

>>> class Key(object): 
...  key = '1' 
...  def __hash__(self): 
...   return 1 
...  def __eq__(self, other): 
...   return hash(self) == hash(other) 
... 
>>> class FakeKey(Key): 
...  key = '2' 
... 
>>> k = Key() 
>>> >>> fk = FakeKey() 
>>> d = {k:k,fk:fk} 
>>> d 
{<__main__.Key object at 0x100489f10>: <__main__.FakeKey object at 0x100489fd0>} 
>>> ref = d[k] 
>>> ref.key 
'2' 
>>> d.keys()[0].key 
'1' 
>>> 

出現我是對的(只出現)。

+0

我沒有數字,我只是在我的解釋器中鍵入了'hash(None)'。查看Ned的回答來回答你關於'hash'的問題。另外,你爲什麼不依賴散列'None'?這是一個內存中的對象,還是Python文檔在某處說的? – orokusaki 2011-03-27 06:34:22

+0

我的意思是,我不會依賴散列值(無)是一致的。在字典中使用無可以,但使用hash(None)產生的值不是。 – 2011-03-27 06:41:44

+0

而且實際上很少有理由需要知道Python對象的散列值。如果你認爲你這樣做,那麼你可能會考慮錯誤的方式。 http://docs.python.org/library/functions.html#hash – 2011-03-27 06:50:46