13

インスタンスをセットに追加してから、そのオブジェクトがそのセットに存在するかどうかを後でテストするという問題が発生しています。オーバーライドしまし__eq__()たが、包含テスト中に呼び出されません。__hash__()代わりにオーバーライドする必要がありますか? __hash__()もしそうなら、タプル、リスト、辞書をハッシュする必要がある場合、どのように実装しますか?

class DummyObj(object):

    def __init__(self, myTuple, myList, myDictionary=None):
        self.myTuple = myTuple
        self.myList = myList
        self.myDictionary = myDictionary

    def __eq__(self, other):
        return self.myTuple == other.myTuple and \
            self.myList == other.myList and \
            self.myDictionary == other.myDictionary

    def __ne__(self, other):
        return not self.__eq__(other)

if __name__ == '__main__':

    list1 = [1, 2, 3]
    t1    = (4, 5, 6)
    d1    = { 7 : True, 8 : True, 9 : True }
    p1 = DummyObj(t1, list1, d1)

    mySet = set()

    mySet.add(p1)

    if p1 in mySet:
        print "p1 in set"
    else:
        print "p1 not in set"
4

2 に答える 2

12

セットに関するドキュメントから:

セット クラスは辞書を使用して実装されます。したがって、セット要素の要件は辞書キーの要件と同じです。つまり、要素が __eq__() と __hash__() の両方を定義していること。

__hash__ 関数のドキュメントでは、コンポーネントのハッシュを一緒に xor することを提案しています。他の人が述べたように、可変オブジェクトをハッシュすることは一般的には良い考えではありませんが、本当に必要な場合はこれでうまくいきます:

class DummyObj(object):

    ...

    def __hash__(self):
        return (hash(self.myTuple) ^
                hash(tuple(self.myList)) ^
                hash(tuple(self.myDictionary.items())))

そして、それが機能するかどうかを確認します:

p1 = DummyObj(t1, list1, d1)
p2 = DummyObj(t1, list1, d1)
mySet = set()
mySet.add(p1)

print "p1 in set", p1 in mySet
print "p2 in set", p2 in mySet

これは以下を出力します:

$ python settest.py 
p1 in set True
p2 in set True
于 2013-03-10T20:14:40.773 に答える
-3

私の推測では、'in' 演算子を使用してオブジェクトを比較するときに、Python によって呼び出される__eq__か、呼び出されない可能性があります。__ne__ドキュメントを見ると、特定の「リッチ比較」演算子が何であるかはわかりませんが__cmp__、より適切な「リッチ比較」演算子が実装されていない場合、Pythonはデフォルトでそれを使用してオブジェクト比較を実行するため、オーバーライドすると問題が解決するはずです。

于 2013-03-10T20:20:44.033 に答える