Pull to refresh

Что вернет операция 1 < 3 < 2?

Reading time2 min
Views562
Ответ: False

Если предположить, что это выражение состоит из двух отдельных операций, то слева на право: 1 < 3 = True, True(понимаем 1) < 2 также долен вернуть True, но почему-то False.

Фишка в том, что 1 < 3 < 2 это не две отдельных операции, а одна сложная. Давайте продизассемблируем (в питоновсеий дизассемблер) наше выражение. Как видим на выходе весьма спицефический код:

from dis import dis

dis(lambda: 1<3<2)
  1           0 LOAD_CONST               1 (1) 
              3 LOAD_CONST               2 (3) 
              6 DUP_TOP              
              7 ROT_THREE            
              8 COMPARE_OP               0 (<) 
             11 JUMP_IF_FALSE_OR_POP    21 
             14 LOAD_CONST               3 (2) 
             17 COMPARE_OP               0 (<) 
             20 RETURN_VALUE         
        >>   21 ROT_TWO              
             22 POP_TOP              
             23 RETURN_VALUE


Разберем, что тут происходит. Загружаем в стек две константы и дублируем последнюю для сравнения потом. Переворачиваем стек. Вытягиваем 2 константы, сравниваем. Кладем результат в стек. Если Фолс, то выходим. Если Тру, то попаем Тру из стека. Загружаем третюю константу, и сравниваем со второй, сдублированой раньше. Можете самостоятельно дизассемблоировать 1 < 2 < 3 < 4… Код будет похож на код выше, только соответствующие блоки будут повторяться. И все равно это будет один сложный оператор.

А вот код 1<3 and 3<2. Он весьма линеен и понятен:

dis(lambda: 1<3 and 3<2)
  1           0 LOAD_CONST               1 (1) 
              3 LOAD_CONST               2 (3) 
              6 COMPARE_OP               0 (<) 
              9 JUMP_IF_FALSE_OR_POP    21 
             12 LOAD_CONST               2 (3) 
             15 LOAD_CONST               3 (2) 
             18 COMPARE_OP               0 (<) 
        >>   21 RETURN_VALUE


Зачем такой оператор нужен, ведь понятьнее писать 1<3 and 3<2. К примеру, я парсил yaml:
age:
  title: Age
  items:
    1: up to 18
    2: 18-25
    3: above 25


Следующим кодом:

def range_age(age):
    for k, v in data['age'].items.items():
        v = v.replace('up to','{}<')
        v = v.replace('above','{}>')
        v = v.replace('-','<={}<=')
        if eval(v.format(age)):
            return k


Всем хорошего дня!

ПС. А есть ли подобные, сложные операторы в других языках?
Tags:
Hubs:
-10
Comments10

Articles