Как реализовать __eq__ для теста включения включения?

У меня возникает проблема, когда я добавляю экземпляр в набор, а затем позже проверяю, существует ли этот объект в этом наборе. Я переопределил __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"

Ответ 1

Из документации по наборам:

Набор классов реализуется с использованием словарей. Соответственно, требования к элементам набора те же, что и для словаря ключи; а именно, что элемент определяет как __eq __(), так и __hash __().

Документация функций __ hash__ предлагает xor-ing хэши компонентов вместе. Как отмечали другие, обычно это не хорошая идея для хеш-изменяемых объектов, но если вам это действительно нужно, это работает:

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

Ответ 2

Ну, я думаю, что __eq__ или __ne__ не может вызываться python при сравнении объектов с помощью оператора in. Я не уверен, что будет конкретным оператором "богатого сравнения", глядя на документацию, но переопределение __cmp__ должно решить вашу проблему, поскольку python использует его по умолчанию для выполнения сравнения объектов, если более подходящим оператором "богатого сравнения" является не реализована.