Какие методы вызывает `foo <bar <baz`? - PullRequest
9 голосов
/ 17 ноября 2010

В питоне мы можем сказать:

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.

Edit: 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 ]

12 голосов
/ 17 ноября 2010
if foo < bar < baz:

эквивалентно

if foo < bar and bar < baz:

с одним важным отличием: если bar является мутирующей, она будет кэширована. I.e.:

if foo < bar() < baz:

эквивалентно

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

Но чтобы ответить на ваш вопрос, он в конечном итоге будет:

if foo.__lt__(bar) and bar.__lt__(baz):
4 голосов
/ 17 ноября 2010

Вы правы:

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
3 голосов
/ 17 ноября 2010

Используются последовательные вызовы для оператора сравнения меньше, чем:

>>> 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        
1 голос
/ 17 ноября 2010

Вызывает специальный метод __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__()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...