Что я делаю неправильно (реализация альтернативного равенства с перегрузкой в ​​python) - PullRequest
1 голос
/ 06 сентября 2011

Человек задал вопрос на SO о том, как получить уникальную функцию списка в python с альтернативной функцией равенства.

Я думал, что это можно сделать, унаследовав от класса элемента и перегрузив функцию равенства

import functools
@functools.total_ordering
class ffloat(float):
def __eq__(self,other):
    if floor(self) == floor(other):
        return True
    else:
        return False
def __le__(self,other):
    if self == other:
        return True
    else:
        return float(self) <= float(other)
def __hash__(self):
    return floor(self)


a = map(ffloat,[4.3,8,8.9, 13])


In [41]: a[1] == a[2]
Out[41]: True

но

In [42]: set(a)
Out[42]: set([4.3, 8.0, 8.9, 13.0])

Редактировать: заменено равенство abs <1.5 равенством полов <BR>Добавлен хэш PS. Есть способ сделать фабрику классов из этого классаи два лямбда и возвращает класс, который наследует от первого, переопределяя необходимую функцию равенства.

1 Ответ

8 голосов
/ 06 сентября 2011

Это не допустимая функция равенства, так как она не транзитивная :

mfloat(0) == mfloat(1) == mfloat(2), но mfloat(0) != mfloat(2).

Также обратите внимание, что дляПри использовании в наборе вы должны переопределить __hash__, чтобы для всех экземпляров a, b вашего класса выполнялось следующее свойство:

a == b ⇒ hash(a) == hash(b)

set обнаруживает, что hash(mfloat(8)) != hash(mfloat(9)).Поскольку set предполагает, что указанное выше свойство выполняется, он делает вывод, что mfloat(8) != mfloat(9) без фактического вызова __eq__.

Таким образом, это работает:

from math import floor
class ffloat(float):
    def __eq__(self,other):
        return floor(self) == floor(other):
    def __hash__(self):
        return floor(self)

a = map(ffloat,[4.3,8,8.9, 13])
print(set(a))
# output: {8.0, 4.3, 13.0}
...