2013-11-01 4 views
5

Я столкнулся с каким-то запутанным поведением методов сравнения магии. Предположим, мы имеем следующий класс:Путаница метода магии Python

class MutNum(object): 
    def __init__ (self, val): 
     self.val = val 

    def setVal(self, newval): 
     self.val = newval 

    def __str__(self): 
     return str(self.val) 

    def __repr__(self): 
     return str(self.val) 

    # methods for comparison with a regular int or float: 
    def __eq__(self, other): 
     return self.val == other 

    def __gt__(self, other): 
     return self.val > other 

    def __lt__(self, other): 
     return self.val < other 

    def __ge__(self, other): 
     return self.__gt__(other) or self.__eq__(other) 

    def __le__(self, other): 
     return self.__lt__(other) or self.__eq__(other) 

класс делает то, что он должен делать, сравнивая объект MutNum на регулярной Int или поплавок не является проблемой. Однако, и это то, что я не понимаю, оно даже сравнивается отлично, когда магическим методам даются два объекта MutNum.

a = MutNum(42) 
b = MutNum(3) 
print(a > b) # True 
print(a >= b) # True 
print(a < b) # False 
print(a <= b) # False 
print(a == b) # False 

Почему это работает? Благодарю.

+1

Это может помочь подумать о '__gt__' и' __lt__', стоящих в том же отношении, что и '__add__' и' __radd__', например. Если первое не применяется, Python пытается использовать другой, если операнды будут отменены. – chepner

ответ

4

Он оценивает следующим образом (с использованием repr -как обозначения вместо ссылки на переменные):

MutNum(42) > MutNum(3) 
=> MutNum(42).__gt__(MutNum(3)) 
=> MutNum(42).val > MutNum(3) 
=> 42 > MutNum(3) 

И оттуда, это просто INT-MutNum Comparision вы уже знаете, работает.

+0

@dust * Вы * сказали, что сравнение обычных int и floats с экземплярами этого класса не является проблемой ;-) '42> ...' не будет вызывать 'MutNum .__ gt__' еще раз, поскольку 42 не является' MutNum'. Такая путаница является одной из причин не определять '__repr__', как у вас, но добавить что-то, что отличает' MutNum' от числа, которое оно обертывает. – delnan

2

Если вы выбросите некоторые принты и/или sys.stderr.write, я думаю, вы увидите, что происходит. EG:

def __gt__(self, other): 
    sys.stderr.write('__gt__\n') 
    sys.stderr.write('{}\n'.format(type(other))) 
    sys.stderr.write('{} {}\n'.format(self.val, other)) 
    result = self.val > other 
    sys.stderr.write('result {}\n'.format(result)) 
    return result 

def __lt__(self, other): 
    sys.stderr.write('__lt__\n') 
    sys.stderr.write('{}\n'.format(type(other))) 
    sys.stderr.write('{} {}\n'.format(self.val, other)) 
    result = self.val < other 
    sys.stderr.write('result {}\n'.format(result)) 
    return result 

При попытке сравнить self.val (целое число) к другому (а MutNum), питон понимает, что это не имеет ничего для сравнения в Int к MutNum, и изменяет порядок сравнения, и сравнивает MutNum с int - это то, что вы определили. То есть, одно> сравнение делает>, как и следовало ожидать, но оно также делает <.

Смежные вопросы