2013-11-01 9 views
5

Ich habe in etwas verwirrendes Verhalten der magischen Vergleichsmethoden gelaufen. Angenommen, wir die folgende Klasse haben:Python magische Methode Verwirrung

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) 

Die Klasse tut, was es tun soll, ein MutNum Objekt zu einem regulären int oder float Vergleich ist kein Problem. Jedoch, und das ist was ich nicht verstehe, es sogar gut vergleicht, wenn den magischen Methoden zwei MutNum-Objekte gegeben werden.

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 

Warum funktioniert das? Vielen Dank.

+1

Es könnte hilfreich sein, sich '__gt__' und' __lt__' vorzustellen, die zum Beispiel in der gleichen Beziehung wie '__add__' und' __radd__' stehen. Wenn das erste nicht zutrifft, versucht Python das andere mit umgekehrten Operanden. – chepner

Antwort

4

Er wertet wie folgt (eine repr -ähnlichen Notation statt Bezug auf Variablen):

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

Und von dort, es ist nur das int-MutNum Vergleich Sie bereits Werke kennen.

+0

@dust * Du * sagte, dass das Vergleichen von regulären Ints und Floats mit Instanzen dieser Klasse kein Problem ist ;-) '42> ...' ruft 'MutNum .__ gt__' nicht erneut auf, da 42 keine' MutNum' ist. Diese Art von Verwirrung ist ein Grund, nicht '__repr__' zu definieren, sondern etwas hinzuzufügen, das' MutNum' von der umbrochenen Zahl unterscheidet. – delnan

2

Wenn Sie einige Drucke und/oder sys.stderr.write's werfen, werden Sie sehen, was passiert. Beispiel:

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 

Wenn Sie versuchen, self.val (int) zu anderen (a MutNum) zu vergleichen, Python realisiert es nichts zum Vergleichen ein int zu einem MutNum hat, und kehrt die Reihenfolge des Vergleichs, und vergleicht eine MutNum mit einem int - was Sie definiert haben. Das heißt, ein einzelner> Vergleich macht das> was Sie erwarten würden, aber es macht auch eine <.