Почему троичный оператор более эффективен в python, чем if-else?

Исследуя некоторый код на python, я пришел к странному выводу, что и if-else, и троичные условные операторы в python приведут к одинаковому количеству исполняемых инструкций байт-кода, однако оператор If-Else будет немного медленнее.


Давайте рассмотрим этот пример функции:

def test(foo):
    bar = 0
    if (foo > 0):
            bar = 1
    else:
            bar = 0
    return bar

После разборки его байт-код выглядит так:

  7           0 LOAD_CONST               1 (0)
              3 STORE_FAST               1 (bar)

  8           6 LOAD_FAST                0 (foo)
              9 LOAD_CONST               1 (0)
             12 COMPARE_OP               4 (>)
             15 POP_JUMP_IF_FALSE       27

  9          18 LOAD_CONST               2 (1)
             21 STORE_FAST               1 (bar)
             24 JUMP_FORWARD             6 (to 33)

 11     >>   27 LOAD_CONST               1 (0)
             30 STORE_FAST               1 (bar)

 12     >>   33 LOAD_FAST                1 (bar)
             36 RETURN_VALUE

Теперь давайте заменим оператор if-else на тернарный оператор, то есть:

def test(foo):
    bar = 0
    bar = 1 if foo > 0 else 0
    return bar

Тогда байт-код выглядит следующим образом:

  7           0 LOAD_CONST               1 (0)
              3 STORE_FAST               1 (bar)

  8           6 LOAD_FAST                0 (foo)
              9 LOAD_CONST               1 (0)
             12 COMPARE_OP               4 (>)
             15 POP_JUMP_IF_FALSE       24
             18 LOAD_CONST               2 (1)
             21 JUMP_FORWARD             3 (to 27)
        >>   24 LOAD_CONST               1 (0)
        >>   27 STORE_FAST               1 (bar)

  9          30 LOAD_FAST                1 (bar)
             33 RETURN_VALUE

Итак, вот разница между 2-мя байтовыми кодами:

Условный оператор

goto .end1 if foo < 0
store 1 in register
store register to bar
goto .end2
.end1
store 0 in register
store register to bar
.end2:
push bar
return

Тернарный оператор

goto .end1 if foo < 0
store 1 in register
goto .end2
.end1
store 0 in register
.end2:
store register to bar
push bar
return

Затем в любом случае обе реализации должны выполнить одинаковое количество операций (11, если условие истинно, 10, если оно ложно).

Однако троичный оператор, по-видимому, значительно быстрее, чем оператор if-else. Я запустил эту функцию 1 миллиард раз, и вот результаты:

  • Утверждение If-Else: 147 секунд
  • Тернарный оператор: 136 секунд

Я что-то пропустил?


Код, используемый для измерения времени выполнения:

import time
size = 1000000000
t0 = time.time()
for k in range(size):
    test(k)
print(time.time() - t0)

Окружение: Python3

ОС: Linux Slackware64 14,2

0 ответов

Другие вопросы по тегам