2012-11-21 39 views
6

我正在嘗試爲字符串創建一個自定義哈希函數。我想按字符頻率按重量對字符串進行哈希處理。所以hiih將產生相同的散列。我可以覆蓋__hash__嗎?Python重寫字符串__hash__

或者正在創建一個包裝類,包含字符串並覆蓋__hash____eq__唯一的方法?

+0

我會使用包裝類。它很好,很明確,並且不會因爲冒充字符串而導致混淆,而完全不同。 – millimoose

+0

@millimoose好點 – darksky

+1

將'str'和'custom_str'混合到一個使用散列作爲鍵的容器中可能會很有趣:) –

回答

4

您希望派生類型具有不同的相等語義。通常採用的方法是定義平等是如何工作的,然後根據派生於此的結構構建哈希方法,因爲哈希值必須與平等相符。這可能是:

import collections 

class FrequencyString(str): 
    @property 
    def normalized(self): 
     try: 
      return self._normalized 
     except AttributeError: 
      self._normalized = normalized = ''.join(sorted(collections.Counter(self).elements())) 
      return normalized 

    def __eq__(self, other): 
     return self.normalized == other.normalized 

    def __hash__(self): 
     return hash(self.normalized) 
+1

假設我創建了一個可以返回散列的自由函數。我將如何在返回的散列位置插入該密鑰? dict = {},dict [5] = value'在位置5插入「值」,還是按'5'? – darksky

+0

將值放在字典*中*意味着改變平等語義,這是正確的方法。您可以交替地將封裝器構造爲一個信封,並將原始字符串作爲實例屬性。 – SingleNegationElimination

0

你的假設是正確的,你不能重寫Python中的基類。雖然可以重寫str()將會執行的操作,但它不適用於字符串文字。

如果你是,如果你想創建寫在Python 2.2看看UserString類代碼自己:http://docs.python.org/2/library/userdict.html#module-UserString

否則,你可以簡單地繼承strunicode

在你的情況簡單地覆蓋如果您想將其用作字典密鑰,則方法已足夠。但是,如果你看的比較比你將不得不覆蓋__eq____cmp__

+0

Argghghh - no,no&no到'UserString' - 這是古老的歷史 - 只是繼承自'str',如'class mystr(str):...' –

+0

它說如果我不需要支持版本的向後兼容性在2.2之前,我可以直接從內置的'str'中進行子類化。這將如何完成?它只是:'class wrapper_class(s​​tr):'?重寫'__hash__'和'__eq__'就足夠了嗎? – darksky

+0

@JonClements你剛剛回答了我的評論的第1部分:)方法重寫呢? '__hash__'和'__eq__'是否足夠? – darksky

0

您可以從str繼承,但因爲這些是不可變的,你必須繼承他們的方式略有不同。很可能你會想從現有的字符串中創建新的字符串,所以你也必須重寫__new__方法。您可能還需要添加額外的特殊方法來打敗Python所做的優化。

這是一個子類化內置strmapstr對象的示例,該對象允許在表單中輕鬆替換佔位符。

+0

你能解釋一下「你很可能想從現有的字符串中創建新的」嗎?我只想創建一個可以傳入'__init__'的字符串,那麼爲什麼我需要'__new__'的子類呢?如果我不這樣怎麼辦? – darksky

+0

那麼你打算如何使用它? – Keith

+0

散列一個鍵中具有相同字符的字符串。該值是所有字符串的列表。密鑰是它們的排序版本。 – darksky