2011-02-18 34 views
0

我有一個基本上包裝列表的類,並且列表顯然不能有散列值。我的想法是生成一個隨機數並將其存儲爲散列值。生成並存儲一個隨機數作爲我班的哈希值是否是一個好主意?

+2

你的意思是你得到一個_TypeError:unhashable type_如果你嘗試使用你的類作爲字典鍵(例如)?看到[這個以前的答案](http://stackoverflow.com/questions/1957396/why-dict-objects-are-unhashable-in-python)爲什麼是這樣的情況。你能提供一些關於你想要做什麼的更多信息嗎? – SteveMc 2011-02-18 21:45:10

回答

1

不是一個好主意。散列碼的一般合約是如果對象A等於對象B,則A.hashCode()等於B.hashCode()。隨着你的建議,這將不會成立。

你可以嘗試使用

  • 列表長度的哈希碼的第一個項目
  • 哈希碼在列表中的哈希碼
  • 和所有項目的所有哈希碼作爲哈希碼

或沿着這些線路的其他東西。

3

如果您有兩個相同的實例,則它們必須返回相同的__hash__值。如果你隨機產生一個,你不能保證這將是這種情況,所以你會得到奇怪的行爲。你可以用一個元組而不是一個列表嗎?你可以忽略散列計算中的列表嗎?如果不相等的物體發生碰撞,則可以。

你應該看到DictionaryKeys爲什麼列表不允許有散列值。

+0

或者,可能會「凍結」這個列表,使其工作。這通常意味着將類列表包裝成一個包裝元組的非常類似的類的淺拷貝。通常使用方法名稱「freeze()」。 – 2011-02-18 21:59:40

+0

只需使用`tuple(yourlist)`就可以做到這一點,它只需要一份清單。它是不可變的,但不知道OP是否需要它是可變的。 – sjr 2011-02-18 22:09:48

+0

如果您在構造函數中生成哈希並將其存儲爲成員數據,則對哈希方法的每次調用自然會從該成員返回相同的值。 – Steve314 2011-02-18 22:22:26

1

正如其他人所說,如果2個對象被認爲是「相等的」,那麼它們必須具有相同的散列值。

您如何爲您的班級定義equals取決於您。如果你只關心參照平等,那麼你可以在__init__上生成一個隨機數,但最好的情況是MyWrapper([1,2,3]) == MyWrapper([1,2,3])False

你不應該使用列表的內容作爲@iluxa這樣的散列的原因是因爲如果你使用你的類作爲字典中的鍵,那麼改變內容以便哈希值改變,它會無法在字典中找到該鍵,因爲它存儲了舊的散列值並正在嘗試查找新的散列值。

綜上所述:

  1. 如果a == b然後hash(a) == hash(b)必須是真實的。
  2. 如果a != b 然後hash(a) != hash(b)應該是 真實的大部分時間用於查找的 性能,但它不 是這樣要求的。
  3. 散列的 值不應該的時間之間改變 它添加到一個 dict(或任何其它基於散列的查找 結構確實上查找不 重新計算散列值) 並試圖的找到它。

最後一部分通常只是簡化爲散列值不應該改變。

0

支持可變容器的散列是合理的 - 但一般規則是,你正在散列當前值,而不是容器。

編輯原則上這是合理的,儘管Python通常會防範它。

甚至還有一種特定的散列技術用於這類任務。 Zobrist hashing基於對容器的每次更改都逐漸計算散列值,以這種方式,無論您如何達到特定值,都會得到相同的散列值。這用於國際象棋程序,通過不同的移動順序來檢測棋盤達到相同狀態的情況,作爲遊戲樹搜索的優化。

這裏的問題是爲什麼要使用基於散列的查找來查找列表?

如果值有所不同,但無論如何你想找到相同的容器,那麼這可能會工作(有碰撞問題) - 但它似乎仍然毫無意義。隨機哈希值只是一種標識符,用於標識您指的是哪個對象。該對象的參考/指針是更好的標識符。如果你還沒有對該對象的引用,你將如何知道要搜索哪個散列值?

如果你想要一個容器的集合,列表是一個比隨機哈希列表字典更好的解決方案。

編輯一個可能的例外是,如果你想要一個列表的集合,其中同一個列表可能被添加多次,但只會在容器中出現一次 - 一組列表實例。在這種情況下,散列應該以對象的引用爲基礎,但我不記得那是如何完成的。

相關問題