In python we can say:
if foo < bar < baz:
do something.
and similarly, we can overload the comparision operators like:
class Bar:
def __lt__(self, other):
do something else
but what methods of the types of the operands of those interval co开发者_StackOverflowmparisions are actually called? is the above equivalent to
if foo.__lt__(bar) and bar.__lt__(baz):
do something.
Edit: re S.Lott, Here's some output that helps to illustrate what actually happens.
>>> 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
>>>
if foo < bar < baz:
is equivalent to
if foo < bar and bar < baz:
with one important distinction: if bar is a mutating, it will be cached. I.e.:
if foo < bar() < baz:
is equivalent to
tmp = bar()
if foo < tmp and tmp < baz:
But to answer your question, it will end up being:
if foo.__lt__(bar) and bar.__lt__(baz):
You are correct:
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
It uses successive calls to the less-than comparison operator:
>>> 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
It calls the special method __lt__()
, and if needed it will call __nonzero__()
to coerce the result of __lt__()
to a boolean. Surprisingly (to me at least), there is no __and__()
method to override the and
operator.
Here's a test program:
#!/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__()
精彩评论