Ваша первая версия занимает больше времени, потому что Python должен выполнять больше работы.
При использовании CPython (реализация Python, которую вы загрузите с python .org или найдет как python
или python3
исполняемый на вашем компьютере), ваш код Python компилируется в байт-код , а затем core оценка l oop выполняет каждый байт-код по очереди в большом l oop. Этот большой l oop реализован в C и скомпилирован в машинный код, подходящий для вашей конкретной архитектуры c OS и CPU. Встроенные типы int
и str
также полностью реализованы в коде C, включая код, который запускается при индексации по ним [...]
или при использовании операторов.
Что делает одну версию быстрой а другой медленный - это относительная скорость операций, выполняемых кодом C, по сравнению с выполнением того же действия с большим количеством кода Python (переведенного в байт-код).
dis
модуль может показать вам, какой байт-код создается (в виде удобочитаемого представления). Вот байт-код для вашей первой функции:
>>> import dis
>>> dis.dis(is_palindrome)
6 0 LOAD_CONST 1 (0)
2 STORE_FAST 1 (result)
7 4 LOAD_FAST 0 (n)
6 STORE_FAST 2 (temp)
8 >> 8 LOAD_FAST 2 (temp)
10 LOAD_CONST 1 (0)
12 COMPARE_OP 4 (>)
14 POP_JUMP_IF_FALSE 46
9 16 LOAD_FAST 1 (result)
18 LOAD_CONST 2 (10)
20 INPLACE_MULTIPLY
22 STORE_FAST 1 (result)
10 24 LOAD_FAST 1 (result)
26 LOAD_FAST 2 (temp)
28 LOAD_CONST 2 (10)
30 BINARY_MODULO
32 INPLACE_ADD
34 STORE_FAST 1 (result)
11 36 LOAD_FAST 2 (temp)
38 LOAD_CONST 2 (10)
40 INPLACE_FLOOR_DIVIDE
42 STORE_FAST 2 (temp)
44 JUMP_ABSOLUTE 8
12 >> 46 LOAD_FAST 1 (result)
48 LOAD_FAST 0 (n)
50 COMPARE_OP 2 (==)
52 RETURN_VALUE
, а это вторая:
>>> dis.dis(is_palindrome_str)
6 0 LOAD_GLOBAL 0 (int)
2 LOAD_GLOBAL 1 (str)
4 LOAD_FAST 0 (n)
6 CALL_FUNCTION 1
8 LOAD_CONST 1 (None)
10 LOAD_CONST 1 (None)
12 LOAD_CONST 2 (-1)
14 BUILD_SLICE 3
16 BINARY_SUBSCR
18 CALL_FUNCTION 1
20 LOAD_FAST 0 (n)
22 COMPARE_OP 2 (==)
24 RETURN_VALUE
Вам не нужно понимать влияние каждого байт-кода в этих выходах, но Вы можете видеть, что один листинг намного больше.
Так что int(str(number)[::-1])
также выполняет много работы, но это быстрее, потому что работа выполняется в нативном коде, который более эффективен, чем большой l oop, который должен обрабатывать все возможные операции с байт-кодом.
Для очень больших чисел может быть более эффективно записать все oop, которые рано выходят, работая извне (возьмите величину число от math.log10(...)
, соедините его с 1 и продвигайтесь к среднему тестированию и возвращению в тот момент, когда вы получите результат False
), но я подозреваю, что даже тогда выигрывает преобразование строк.
Единственное улучшение small , которое я могу предложить, заключается в том, что вы не конвертируете обратно в int()
:
def is_palindrome_str_faster(n):
return (v := str(n)) == v[::-1]
Выше (ab) использует синтаксис выражения присваивания Python 3 х . Вы также можете записать это как:
def is_palindrome_str_faster(n):
v = str(n)
return v == v[::-1]
практически без разницы в произведенном байт-коде или производительности.
Использование timeit
модуля для сравнения методов:
>>> timeit('ip(12345654321)', 'from __main__ import is_palindrome as ip')
1.8687424899544567
>>> timeit('ip(12345654321)', 'from __main__ import is_palindrome_str as ip')
0.5467583388090134
>>> timeit('ip(12345654321)', 'from __main__ import is_palindrome_str_faster as ip')
0.42572025093249977