Выполнение этого в проверке экспоненты замедлит случаи, когда это не простая степень двойки, а вовсе не выигрыш. Однако в случаях, когда показатель степени известен заранее (например, используется литерал 2), сгенерированный байт-код может быть оптимизирован с помощью простой оптимизации глазка. Предположительно, это просто не считалось целесообразным (это довольно конкретный случай).
Вот краткое доказательство концепции, которая выполняет такую оптимизацию (может использоваться в качестве декоратора). Примечание: для запуска вам понадобится модуль byteplay .
import byteplay, timeit
def optimise(func):
c = byteplay.Code.from_code(func.func_code)
prev=None
for i, (op, arg) in enumerate(c.code):
if op == byteplay.BINARY_POWER:
if c.code[i-1] == (byteplay.LOAD_CONST, 2):
c.code[i-1] = (byteplay.DUP_TOP, None)
c.code[i] = (byteplay.BINARY_MULTIPLY, None)
func.func_code = c.to_code()
return func
def square(x):
return x**2
print "Unoptimised :", timeit.Timer('square(10)','from __main__ import square').timeit(10000000)
square = optimise(square)
print "Optimised :", timeit.Timer('square(10)','from __main__ import square').timeit(10000000)
Что дает время:
Unoptimised : 6.42024898529
Optimised : 4.52667593956
[Изменить]
На самом деле, если подумать об этом, есть очень веская причина, почему эта оптимизация еще не закончена. Нет никаких гарантий, что кто-то не создаст пользовательский класс, который переопределяет методы __mul__
и __pow__
и будет делать что-то свое для каждого. Единственный способ сделать это безопасно, если вы можете гарантировать, что объект на вершине стека имеет тот же результат "x **2
" и "x*x
", но решить его намного сложнее. Например. в моем примере это невозможно, так как любой объект может быть передан функции квадрат.