为什么在编译为字节码之前,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
这应该被优化。