2010-11-17 41 views
9

Trong python chúng ta có thể nói:phương thức `foo <bar <baz` thực sự gọi là gì?

if foo < bar < baz: 
    do something. 

và tương tự, chúng ta có thể quá tải các toán tử so sánh như:

class Bar: 
    def __lt__(self, other): 
     do something else 

nhưng những gì các phương pháp của các loại toán hạng của những comparisions khoảng đang thực sự được gọi là? là trên tương đương với

if foo.__lt__(bar) and bar.__lt__(baz): 
    do something. 

Chỉnh sửa: lại S.Lott, Đây là một số đầu ra giúp minh họa điều thực sự xảy ra.

>>> class Bar: 
    def __init__(self, name): 
     self.name = name 
     print('__init__', self.name) 
    def __lt__(self, other): 
     print('__lt__', self.name, other.name) 
     return self.name < other.name 

>>> Bar('a') < Bar('b') < Bar('c') 
('__init__', 'a') 
('__init__', 'b') 
('__lt__', 'a', 'b') 
('__init__', 'c') 
('__lt__', 'b', 'c') 
True 
>>> Bar('b') < Bar('a') < Bar('c') 
('__init__', 'b') 
('__init__', 'a') 
('__lt__', 'b', 'a') 
False 
>>> 
+0

+1: Bạn có thể (và đã làm) trả lời câu hỏi của riêng bạn. -1: Bạn chắc chắn không cần phải hỏi điều này ở đây, vì việc tìm kiếm câu trả lời rõ ràng dễ dàng hơn và nhanh hơn so với yêu cầu. –

Trả lời

4

Bạn là chính xác:

class Bar: 
    def __init__(self, name): 
     self.name = name 
    def __lt__(self, other): 
     print('__lt__', self.name, other.name) 
     return True 

a,b,c = Bar('a'), Bar('b'), Bar('c') 

a < b < c 

Output :

('__lt__', 'a', 'b') 
('__lt__', 'b', 'c') 
True 
+0

đến một mức độ nhất định, tôi cũng rất quan tâm đến thời tiết 'và' đang được sử dụng, hoặc một số điều thông minh khác cũng đang diễn ra. – SingleNegationElimination

+0

Với một số thử nghiệm, có vẻ như nó phải làm một cái gì đó về cơ bản tương tự. Tôi có thể sắp xếp cho lần so sánh thứ hai ngắn mạch bằng cách có lần đầu tiên là sai. – SingleNegationElimination

+0

@TokenMacGuy: Như bạn có thể thấy trong ví dụ thứ hai của tôi, nó đơn giản hơn một chút và vì thanh có thể là một hàm biến đổi. –

12
if foo < bar < baz: 

tương đương với

if foo < bar and bar < baz: 

với một khác biệt quan trọng: nếu thanh là một mutating, nó sẽ được lưu trữ. Ví dụ:

if foo < bar() < baz: 

tương đương với

tmp = bar() 
if foo < tmp and tmp < baz: 

Nhưng để trả lời câu hỏi của bạn, nó sẽ kết thúc hạnh phúc:

if foo.__lt__(bar) and bar.__lt__(baz): 
+0

Ồ, ba dòng đầu tiên của bài đăng của tôi sẽ giống như của bạn, ngoại trừ một dấu hai chấm đơn. +1 cho bạn. ;) –

1

Nó gọi phương thức đặc biệt __lt__(), và nếu cần thiết nó sẽ gọi __nonzero__() để ép buộc kết quả của __lt__() để một boolean. Đáng ngạc nhiên (với tôi ít nhất), không có phương pháp __and__() để ghi đè lên toán tử and.

Dưới đây là một chương trình thử nghiệm:

#!/usr/bin/env python 

class Bar: 
    def __init__(self, value): 
     self.value = value 

    def __lt__(self, other): 
     print "%s.__lt__(%s)" % (self, other) 
     return Bar("%s.__lt__(%s)" % (self, other)) 

    def __nonzero__(self): 
     print "%s.__nonzero__()" % (self) 
     return True 

    def __str__(self): 
     return self.value 

foo = Bar("foo") 
bar = Bar("bar") 
baz = Bar("baz") 

if foo < bar < baz: 
    pass 

Output:

foo.__lt__(bar) 
foo.__lt__(bar).__nonzero__() 
bar.__lt__(baz) 
bar.__lt__(baz).__nonzero__() 
+0

'và' không phải là toán tử trong ngữ cảnh này, đó là cơ chế để mô tả luồng điều khiển (rõ ràng trong một ngữ cảnh khác có một bit' và', có toán tử thích hợp và ghi đè '__and__'). Hãy nhớ rằng 'và' không thực sự so sánh bất cứ thứ gì, nó chỉ đánh giá từng thành viên của biểu thức cho sự thật, và khi nó tìm thấy một biểu tượng sai thì nó sẽ bị loại bỏ. Yêu cầu phương thức ghi đè 'và' giống như yêu cầu phương thức ghi đè' if'. –

3

Nó sử dụng cuộc gọi liên tiếp cho người vận hành ít hơn so sánh:

>>> import dis 
>>> def foo(a,b,c): 
...  return a < b < c 
... 
>>> dis.dis(foo) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (b) 
       6 DUP_TOP    
       7 ROT_THREE   
       8 COMPARE_OP    0 (<) 
      11 JUMP_IF_FALSE   8 (to 22) 
      14 POP_TOP    
      15 LOAD_FAST    2 (c) 
      18 COMPARE_OP    0 (<) 
      21 RETURN_VALUE   
     >> 22 ROT_TWO    
      23 POP_TOP    
      24 RETURN_VALUE   
+0

+1 cho mã được tạo. Điều này chỉ củng cố rằng cú pháp cutsy mà tôi đã lên kế hoạch cho một lớp học sẽ không xảy ra một cách an toàn. Nhưng tôi đã học được rất nhiều điều đáng để xem xét. – SingleNegationElimination

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