为什么在编译为字节码之前,Python不计算常量数运算?

在下面的代码中,为什么Python不将f2编译为与f1相同的字节码?

有没有理由不?

 >>> def f1(x): x*100 >>> dis.dis(f1) 2 0 LOAD_FAST 0 (x) 3 LOAD_CONST 1 (100) 6 BINARY_MULTIPLY 7 POP_TOP 8 LOAD_CONST 0 (None) 11 RETURN_VALUE >>> def f2(x): x*10*10 >>> dis.dis(f2) 2 0 LOAD_FAST 0 (x) 3 LOAD_CONST 1 (10) 6 BINARY_MULTIPLY 7 LOAD_CONST 1 (10) 10 BINARY_MULTIPLY 11 POP_TOP 12 LOAD_CONST 0 (None) 15 RETURN_VALUE 

这是因为x可能有一个带有副作用的__mul__方法。 x * 10 * 10调用__mul__两次,而x * 100只调用一次:

 >>> class Foo(object): ... def __init__ (self): ... self.val = 5 ... def __mul__ (self, other): ... print "Called __mul__: %s" % (other) ... self.val = self.val * other ... return self ... >>> a = Foo() >>> a * 10 * 10 Called __mul__: 10 Called __mul__: 10 <__main__.Foo object at 0x1017c4990> 

自动折叠常量,只调用一次__mul__就可以改变行为。

您可以通过重新sorting操作来获得所需的优化,使得常量先乘(或者,如注释中所述,使用括号将它们分组,使得它们仅在一起操作,而不pipe位置),从而使得对折叠发生的欲望:

 >>> def f1(x): ... return 10 * 10 * x ... >>> dis.dis(f1) 2 0 LOAD_CONST 2 (100) 3 LOAD_FAST 0 (x) 6 BINARY_MULTIPLY 7 RETURN_VALUE 

Python 从左向右评估expression式。 对于f2() ,这意味着它将首先计算x*10 ,然后将结果乘以10.尝试:

尝试:

 def f2(x): 10*10*x 

这应该被优化。