2010-08-27 21 views
48

Vì Python không cung cấp các phiên bản trái/phải của các toán tử so sánh, nên nó quyết định chức năng nào để gọi?Cách __eq__ được xử lý bằng Python và theo thứ tự nào?

class A(object): 
    def __eq__(self, other): 
     print "A __eq__ called" 
     return self.value == other 
class B(object): 
    def __eq__(self, other): 
     print "B __eq__ called" 
     return self.value == other 

>>> a = A() 
>>> a.value = 3 
>>> b = B() 
>>> b.value = 4 
>>> a == b 
"A __eq__ called" 
"B __eq__ called" 
False 

Điều này dường như gọi cả hai chức năng __eq__. Chỉ cần tìm cây quyết định chính thức.

Trả lời

63

Biểu thức a == b gọi A.__eq__, vì nó tồn tại. Mã của nó bao gồm self.value == other. Vì int không biết cách so sánh với B, Python cố gắng gọi B.__eq__ để xem liệu nó có biết cách so sánh chính nó với một int hay không.

Nếu bạn sửa đổi mã của bạn để hiển thị những gì giá trị đang được so sánh:

class A(object): 
    def __eq__(self, other): 
     print "A __eq__ called: %r == %r ?" % (self, other) 
     return self.value == other 
class B(object): 
    def __eq__(self, other): 
     print "B __eq__ called: %r == %r ?" % (self, other) 
     return self.value == other 

a = A() 
a.value = 3 
b = B() 
b.value = 4 
a == b 

nó sẽ in:

A __eq__ called: <__main__.A object at 0x013BA070> == <__main__.B object at 0x013BA090> ? 
B __eq__ called: <__main__.B object at 0x013BA090> == 3 ? 
+9

Hoàn toàn đúng. Và tóm lại, những bài kiểm tra đó có lẽ nên là "return self.value == other.value". –

+0

Cảm ơn Ned! Chỉ cần một số Guy: Nó phụ thuộc vào những gì bạn đang tìm kiếm. Ví dụ, giả sử tôi muốn: a == 3 và a == b cho cả hai là đúng (với b.value thay đổi thành 3). – PyProg

46

Khi Python2.x thấy a == b, nó cố gắng sau.

  • Nếu type(b) là một lớp học kiểu mới, và type(b) là một lớp con của type(a), và type(b) đã ghi đè __eq__, sau đó kết quả là b.__eq__(a).
  • Nếu type(a) đã ghi đè __eq__ (nghĩa là, type(a).__eq__ không phải là object.__eq__), thì kết quả là a.__eq__(b).
  • Nếu type(b) đã ghi đè __eq__, thì kết quả là b.__eq__(a).
  • Nếu không có trường hợp nào ở trên, Python lặp lại quá trình tìm kiếm __cmp__. Nếu nó tồn tại, các đối tượng bằng iff nó trả về zero.
  • Là dự phòng cuối cùng, Python gọi object.__eq__(a, b), là True iff ab là cùng một đối tượng.

Nếu bất kỳ phương pháp đặc biệt nào trả về NotImplemented, Python hoạt động như thể phương pháp này không tồn tại.

Lưu ý rằng bước cuối cùng một cách cẩn thận: nếu không a cũng không b quá tải ==, thì a == b cũng giống như a is b.


Từ https://eev.ee/blog/2012/03/24/python-faq-equality/

Nó sẽ giúp ai đó, hy vọng.

+3

Thứ tự trong python 3 là gì? Và thứ tự python 2 được ghi lại ở đâu? – max

+0

Uhh có vẻ như python 3 tài liệu không chính xác. Xem http://bugs.python.org/issue4395 và bản vá để làm rõ. TLDR: phân lớp vẫn được so sánh đầu tiên, ngay cả khi nó trên rhs. – max

+0

Xin chào kev, bài đăng hay.Bạn có thể giải thích nơi mà điểm đầu tiên được ghi lại và tại sao nó được thiết kế như thế? – wim