2013-11-01 18 views
5

Tôi đã gặp một số hành vi khó hiểu của các phương pháp so sánh ma thuật. Giả sử chúng ta có lớp sau đây:Sự nhầm lẫn về phương pháp ma thuật 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) 

Lớp làm những gì nó là vụ phải làm, so sánh một đối tượng MutNum đến một float int hoặc thường xuyên là không có vấn đề. Tuy nhiên, và đây là những gì tôi không hiểu, nó thậm chí còn so sánh tốt khi các phương pháp ma thuật được đưa ra hai đối tượng 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 

Tại sao tính năng này hoạt động? Cảm ơn.

+1

Ví dụ: có thể giúp suy nghĩ về '__gt__' và' __lt__' trong cùng một mối quan hệ với '__add__' và' __radd__'. Nếu cái đầu tiên không áp dụng, Python sẽ thử cái kia với các toán hạng được đảo ngược. – chepner

Trả lời

4

Nó đánh giá như sau (sử dụng một ký hiệu repr -like thay vì đề cập đến các biến):

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

Và từ đó, nó chỉ là the-MutNum int so sánh bạn đã biết công trình.

+0

@dust * Bạn * cho biết so sánh các ints và float thông thường với các cá thể của lớp này không phải là vấn đề ;-) '42> ...' sẽ không gọi 'MutNum .__ gt__' lần nữa vì 42 không phải là' MutNum'. Loại lộn xộn này là một lý do để không định nghĩa '__repr__' như bạn có, nhưng thêm một cái gì đó mà distinguihes' MutNum's từ số nó kết thúc tốt đẹp. – delnan

2

Nếu bạn ném vào một số bản in và/hoặc sys.stderr.write, tôi nghĩ bạn sẽ thấy những gì đang xảy ra. 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 

Khi bạn cố gắng để so sánh self.val (một int) để khác (một MutNum), trăn nhận ra nó không có gì để so sánh một int để một MutNum, và đảo ngược thứ tự của các so sánh, và so sánh một MutNum với một int - đó là một cái gì đó bạn đã xác định. Tức là, một đơn> so sánh đang thực hiện> như bạn mong đợi, nhưng nó cũng đang thực hiện một <.

Các vấn đề liên quan