2011-07-11 84 views
9

Mark Ransom在回答上SO question about hashes這裏SO:需要說明有關哈希的解釋對象

[...]一個 對象是哈希的,如果它有一個哈希值期間 其生命週期從不改變 。所以根據官方的定義,即使它有一個__hash__()函數,任何可變結果都不能排除。關於這兩項要求的我的陳述 是不真實的,因爲 可排除已經意味着要求是不可變的。

我想確定,我說得對 - 即使不是母語的人 - 所以我希望有人糾正我,如果我錯了。

假設該類

class Author(object): 
    def __init__(self, id, name, age): 
     self.id = id 
     self.name = name 
     self.age = age 

    def __eq__(self, other): 
     return self.id==other.id\ 
       and self.name==other.name 

    def __hash__(self): 
     return hash(('id', self.id, 
        'name', self.name)) 

我明白,__eq__讓我與==操作比較這個類的對象。從Marks的答案我明白,即使我的對象peter = Author(1, "Peter", 33)有一個__hash__它不可散列,因爲我可能可以做一些像peter.age = 43這意味着它不是不可變的。所以我的Author類的對象是不可散列的,因此在例如字典中不可用作鍵。我看起來是對的還是看起來,我需要更多的解釋?這個類的:-)

回答

10

實例是哈希的,如果你承諾永不復位idname他們。你不能保證這些屬性永遠不會被重置,Python原理"we are all consenting adults here",但提供重置__hash__所依賴的屬性的方法將是非常糟糕的風格。

例如,如果您提供對Author實例一set_name方法,但沒有set_id,那麼類的客戶端可以有理由認爲__hash__工作僅在id

如果你想講清楚的Author客戶,他們不應該重置某些屬性,則可以通過前置一個_它的名字標籤是私有的。然後,如果您還想要提供(只讀)訪問使用其通用名稱的屬性,你可以把它property

class Author(object): 
    def __init__(self, id, name, age): 
     self._id = id 
     self._name = name 
     self.age = age  # ages tend to change, so mutable 

    id = property(lambda self: self._id) 
    name = property(lambda self: self._name) 

    def __eq__(self, other): 
     return self.id==other.id\ 
       and self.name==other.name 

    def __hash__(self): 
     return hash(('id', self.id, 
        'name', self.name)) 
+0

如果我改變'age'對象被看作是*不會改變*? – Aufwind

+0

@Druss:是的,因爲您在確定相等或散列鍵時沒有考慮它。我會在一秒鐘之內用更多的建議更新答案。 –

+0

@Druss:正確。 –