Почему этот метод тестирования на палиндромы намного медленнее?

У меня есть два разных метода тестирования на палиндром. Одним из них является следующее:

def palindrome(text):
    return text == text[::-1]

Очень просто, конечно, но я предполагал, что это будет медленно, поскольку он (безусловно) должен хранить значение text[::-1] где-то после изменения его, затем он проверяет каждый символ в обоих. Итак, я попробовал другой метод:

def palindrome_2(text):
    left = 0
    right = len(text) - 1
    while left < right:
        if text[left] != text[right]:
            return False
        right -= 1
        left += 1
    return True

Он начинается в начальной и конечной точках и проходит в центр. Насколько я могу судить, это должно быть быстрее, поскольку проверяет только [0, n // 2) и наоборот для конца. Тем не менее, когда я использую timeit для тестирования, первым 0.32 а второй 1.34, Зачем?

1 ответ

Решение

Я думаю, что это полезно для использования dis чтобы взглянуть на полученный здесь байт-код:

import dis
dis.dis(palindrome)
dis.dis(palindrome_2)

Палиндром:

  4           0 LOAD_FAST                0 (text)
              3 LOAD_FAST                0 (text)
              6 LOAD_CONST               0 (None)
              9 LOAD_CONST               0 (None)
             12 LOAD_CONST               2 (-1)
             15 BUILD_SLICE              3
             18 BINARY_SUBSCR
             19 COMPARE_OP               2 (==)
             22 RETURN_VALUE

Palindrome_2:

 10           0 LOAD_CONST               1 (0)
              3 STORE_FAST               1 (left)

 11           6 LOAD_GLOBAL              0 (len)
              9 LOAD_FAST                0 (text)
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 LOAD_CONST               2 (1)
             18 BINARY_SUBTRACT
             19 STORE_FAST               2 (right)

 12          22 SETUP_LOOP              60 (to 85)
        >>   25 LOAD_FAST                1 (left)
             28 LOAD_FAST                2 (right)
             31 COMPARE_OP               0 (<)
             34 POP_JUMP_IF_FALSE       84

 13          37 LOAD_FAST                0 (text)
             40 LOAD_FAST                1 (left)
             43 BINARY_SUBSCR
             44 LOAD_FAST                0 (text)
             47 LOAD_FAST                2 (right)
             50 BINARY_SUBSCR
             51 COMPARE_OP               3 (!=)
             54 POP_JUMP_IF_FALSE       61

 14          57 LOAD_CONST               3 (False)
             60 RETURN_VALUE

 15     >>   61 LOAD_FAST                2 (right)
             64 LOAD_CONST               2 (1)
             67 INPLACE_SUBTRACT
             68 STORE_FAST               2 (right)

 16          71 LOAD_FAST                1 (left)
             74 LOAD_CONST               2 (1)
             77 INPLACE_ADD
             78 STORE_FAST               1 (left)
             81 JUMP_ABSOLUTE           25
        >>   84 POP_BLOCK

 17     >>   85 LOAD_CONST               4 (True)
             88 RETURN_VALUE

По сути, при выполнении одинакового объема работы C-код будет быстрее, чем соответствующий Python-код. Как вы можете видеть, первый подход вызывает встроенную функцию, которая написана на быстром языке C. Вторая функция должна выполнять большую часть работы в коде Python, включая обработку накладных расходов циклической конструкции, которая будет медленнее, чем вызов C.

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