2011-02-14 4 views
2

問題を正しく処理しています。私は、すべての追加Fooのオブジェクトがため、同じ内容、同じハッシュを持っているので、単一の要素を含むように設定し、結果を期待する同じハッシュ値ですが、__hash__をオーバーライドした後に同じオブジェクトではない

class Foo: 
    def __init__(self, bar): 
     self.keys = list(bar.keys()) 
     self.values = list(bar.values())  
    def __str__(self): 
     return ', '.join('%s: %s' % z for z in zip(self.keys, self.values))  
    def __hash__(self): 
     return hash(str(self)) 

if __name__ == '__main__': 
    result = set() 
    d = { 1: 2, 3: 4, 5: 6, 7: 8 } 
    for i in range(10): 
     result.add(Foo(d)) 
    for r in result: 
     print r, hash(r) 

:次のコードを考えてみましょう。

しかし、これが結果です:

[email protected]:~/Desktop/stackoverflow$ python hashproblem.py 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 
1: 2, 3: 4, 5: 6, 7: 8 2131119371379196338 

ここでの問題は何ですか? と同じように見えるので、組み込みのsetオブジェクトで重複として扱わないでください。セットに重複が含まれているのはなぜですか?

私は、Foo(d)の代わりにstr(Foo(d))を使用して要素をセットに追加すると、物事が期待どおりに機能することに気付きました。なぜそれは重要ですか?

Pythonのバージョンは次のとおりです。

[email protected]:~/Desktop/stackoverflow$ python --version 
Python 2.6.6 

答えて

4

__hash__方法は、内部ハッシュテーブルのために使用しているので、あなたにも__eq__を再定義する必要があります。

オーバーライドのみ__eq__も正しくありません。 2つのオブジェクトが等しい場合、つまりa.__eq__(b) == Trueの場合、hash(a)hash(b)の両方が同じでなければなりません。

デフォルト__hash__方法は次のとおりです。

def __hash__(self): 
    return id(self) 
+0

ありがとうございます!それはうまくいくようです。 '__hash__'をオーバーライドする必要がありますか、十分に' __eq__'ですか? – misha

+0

@misha、オブジェクトのデフォルトの '__hash__'は' return id(self) 'です。オーバーライドが厳密に必要なわけではありません。 – vz0

+0

私は '__eq__'を実装していて、' __hash__'を実装していないと思うと、この例は壊れてしまいます。 'Foo(d)'は10個の新しい 'Foo'インスタンスを作成しています。おそらく、 'dict'実装は、同じハッシュバケット内の等しいキーだけを探します。 – Mikel