Python 3 предварительно вычисляет значение 2 ** 0.5
во время компиляции, так как оба операнда известны в это время. Однако значение sqrt
не известно во время компиляции, поэтому вычисления обязательно происходят во время выполнения.
Вы не учитываете, сколько времени потребуется для вычисления 2 ** 0.5
, но только время, необходимое для загрузки константы.
Более справедливое сравнение было бы
$ python3 -m timeit -s "from math import sqrt" "sqrt(2)"
5000000 loops, best of 5: 50.7 nsec per loop
$ python3 -m timeit -s "x = 2" "x**0.5"
5000000 loops, best of 5: 56.7 nsec per loop
Я не уверен, есть ли способ показать неоптимизированный байт-код. Python начинается с синтаксического анализа исходного кода в абстрактное синтаксическое дерево (AST):
>>> ast.dump(ast.parse("2**0.5"))
'Module(body=[Expr(value=BinOp(left=Num(n=2), op=Pow(), right=Num(n=0.5)))])'
Обновление : эта конкретная оптимизация теперь применяется непосредственно к абстрактному синтаксическому дереву , поэтому байтовый код создается непосредственно из чего-то вроде
Module(body=Num(n= 1.4142135623730951))
Модуль ast
, похоже, не применяет оптимизацию.
Компилятор принимает AST и генерирует неоптимизированный байт-код; в этом случае, я полагаю, что это будет выглядеть (на основе вывода dis.dis("2**x")
и dis.dis("x**0.5")
) как
LOAD_CONST 0 (2)
LOAD_CONST 1 (0.5)
BINARY_POWER
RETURN_VALUE
Необработанный байт-код может быть изменен Оптимизатор глазка, который может уменьшить эти 4 инструкции до 2, как показано в модуле dis
.
Затем компилятор генерирует байтовый код из AST.
>>> dis.dis("2**0.5")
1 0 LOAD_CONST 0 (1.4142135623730951)
2 RETURN_VALUE
[ Хотя следующий абзац изначально был написан с целью оптимизации байт-кода, рассуждения применимы и к оптимизации AST.]
Поскольку во время выполнения ничто не влияет на то, как два LOAD_CONST
и следующие BINARY_POWER
оцениваются инструкции (например, нет поиска имени), оптимизатор глазка может взять эту последовательность байтовых кодов, выполнить вычисление самого 2**0.5
и заменить первые три инструкции одной инструкцией LOAD_CONST
, которая загружает результат немедленно.