Доступ к исходному сравнению int из класса, производного от int, с перегруженным оператором сравнения

У меня есть класс, производный от int, с перегруженным оператором сравнения.

В теле перегруженных методов мне нужно использовать исходный оператор.

Пример игрушки:

>>> class Derived(int):
...     def __eq__(self, other):
...         return super(Derived, self).__eq__(other)

отлично работает с Python 3.3+, но не работает с Python 2.7 с исключением AttributeError: 'super' object has no attribute '__eq__'.

Я могу вспомнить несколько обходных путей, которые показались мне не очень чистыми:

return int(self) == other

требует создания нового объекта int только для его сравнения, а

try:
    return super(Derived, self).__eq__(other)
except AttributeError:
    return super(Derived, self).__cmp__(other) == 0

разделяет поток управления на основе версии Python, которую я нахожу ужасно беспорядочной (так же как и явную проверку версии Python).

Как я могу получить доступ к исходному целочисленному сравнению элегантным способом, работая с Python 2.7 и 3.3+?


person abukaj    schedule 28.11.2016    source источник
comment
Вы можете получить доступ к методу сравнения int через super.__eq__ . Однако в зависимости от версии Python методы сравнения встроенных типов реализуются сильно по-разному. Поэтому python2 super.eq требует 1 аргумент (другой), тогда как python3 требует 2 (я и другой)   -  person infotoni91    schedule 01.12.2016
comment
Считаете ли вы int(self) == int(other) слишком грязным?   -  person Phillip    schedule 01.12.2016
comment
@Phillip, он создает на один объект больше, чем int(self) == other   -  person abukaj    schedule 01.12.2016
comment
@abukaj А, ты уже думал об этом. Извиняюсь. Я не думаю, что накладные расходы, которые вы предполагаете, реальны. Было бы безумием для любой реализации Python не оптимизировать встроенный целочисленный тип, например, действительно создавать экземпляр полноценного объекта каждый раз, когда у вас где-то есть целое число. (То есть, я бы провел некоторое тестирование, прежде чем продолжать беспокоиться об этой оптимизации.)   -  person Phillip    schedule 01.12.2016


Ответы (4)


Я считаю, что вы должны определить __eq__ в int перед определением класса. Например:

int = 5
def int.__eq__(self, other):
    return self.real == other
IntDerived = Derived(int)

Это должно дать классу super атрибут __eq__.


ОТРЕДАКТИРОВАНО


Основная идея сработала, но мне сообщили, что код не работает. Итак: улучшенный код:

class Derived(int):
    def __eq__(self, other):
        return self.real == other

Int = 5
D = Derived(Int)
D.__eq__(4) #Output: False
D.__eq__(5) #Output: True
person GreenHawk1220    schedule 07.12.2016
comment
Это не питон. - person Stop harming Monica; 07.12.2016
comment
@GreenHawk1220 GreenHawk1220 Я приму ответ, если вы поместите метод __eq__() в определение класса Derived (и заставите его работать в Python). Идея доступа к атрибуту .real работает, но код не Python. - person abukaj; 09.12.2016
comment
Рад, что помог. Бог благословил. - person GreenHawk1220; 09.12.2016

Python 2 и 3 значительно отличаются друг от друга, поэтому я думаю, что вам следует стиснуть зубы и проверить версии. Этого следует ожидать только в том случае, если вы пытаетесь написать код, который работает на обоих (по моему опыту, рано или поздно вы найдете что-то, что нужно исправить). Чтобы избежать какого-либо влияния на производительность, вы можете сделать что-то вроде:

from six import PY2

class Derived(int):
    if PY2:
        def __eq__(self, other):
            return super(Derived, self).__cmp__(other) == 0
    else:
        def __eq__(self, other):
            return super(Derived, self).__eq__(other)

Я бы так и сделал. Если бы я действительно хотел создать подкласс int...

Если вы действительно не хотите, возможно, вы могли бы попробовать:

class Derived(int):
    def __eq__(self, other):
        return (self ^ other) == 0

Очевидно, что если вы заботитесь о производительности, вам придется выполнить профилирование остального кода и выяснить, не является ли какой-либо из них значительно хуже...

person daphtdazz    schedule 02.12.2016
comment
Мне нравится последний подход, однако он не работает, когда other является числом с плавающей запятой. - person abukaj; 09.12.2016

Обе версии реализуют метод __xor__, вы можете попробовать это:

class Derived(int):
    def __eq__(self, other):
        return not super(Derived, self).__xor__(other)
person joebeeson    schedule 07.12.2016
comment
Мне нравится ответ. Однако не очень чисто и не работает по сравнению с float. Также я думаю, что нет необходимости создавать объект super, достаточно self. self ^ other может быть еще проще. - person abukaj; 09.12.2016

использование hasattr позволяет избежать создания нового объекта int, перехвата исключения или явной проверки версии Python.

Приведенный ниже код работает как на Python 2.7, так и на 3.3+:

class Derived(int):
    def __eq__(self, other):
        return super(Derived, self).__cmp__(other) == 0 if hasattr(Derived, "__cmp__") else super(Derived, self).__eq__(other)
person Derorrist    schedule 07.12.2016