在指数检验中这样做会减缓不是简单的二次幂的情况,所以不一定是胜利。然而,在指数预先已知的情况下(例如使用文字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”,但是要解决这个问题要困难得多。在我的例子中,这是不可能的,因为任何对象都可以传递给square函数。