什么方法`foo<吧<巴兹`实际上是在调用?

时间:2010-11-17 01:55:03

标签: python operator-overloading

在python中我们可以说:

if foo < bar < baz:
    do something.

同样,我们可以重载比较运算符,如:

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

但实际上调用了那些区间比较的操作数类型的哪些方法?以上等同于

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

编辑:re S.Lott,这是一些有助于说明实际情况的输出。

>>> 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
>>> 

4 个答案:

答案 0 :(得分:12)

if foo < bar < baz:

相当于

if foo < bar and bar < baz:

有一个重要的区别:如果bar是变异的,它将被缓存。即:

if foo < bar() < baz:

相当于

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

但要回答你的问题,它最终会成为:

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

答案 1 :(得分:4)

你是对的:

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

输出:

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

答案 2 :(得分:3)

它使用对小于比较运算符的连续调用:

>>> 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        

答案 3 :(得分:1)

它调用特殊方法__lt__(),如果需要,它将调用__nonzero__()__lt__()的结果强制转换为布尔值。令人惊讶的是(至少对我来说),没有__and__()方法来覆盖and运算符。

这是一个测试程序:

#!/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

输出:

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