考虑以下Python 2代码
numbers = []
def excludeMax():
while True:
result = input('Enter next number or end:')
if (result == 'end'):
break
else:
numbers.append(result)
numbers.sort()
sum_numbers = sum(numbers[:-1])
我的电脑上的输出是
from timeit import default_timer
def floor():
for _ in xrange(10**7):
1 * 12 // 39 * 2 // 39 * 23 - 234
def normal():
for _ in xrange(10**7):
1 * 12 / 39 * 2 / 39 * 23 - 234
t1 = default_timer()
floor()
t2 = default_timer()
normal()
t3 = default_timer()
print 'Floor %.3f' % (t2 - t1)
print 'Normal %.3f' % (t3 - t2)
那么,当他们两个都做同样的事情时,为什么地板除法运算符Floor 0.254
Normal 1.766
比普通除法运算符//
更快?
答案 0 :(得分:4)
Python解释器在floor
中预先计算循环内的表达式,但不在normal
中预计算。
这里是地板的代码:
>>> dis.dis(floor)
5 0 SETUP_LOOP 24 (to 27)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_CONST 9 (10000000)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 10 (to 26)
16 STORE_FAST 0 (_)
6 19 LOAD_CONST 15 (-234)
22 POP_TOP
23 JUMP_ABSOLUTE 13
>> 26 POP_BLOCK
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE
您可以看到表达式已经计算LOAD_CONST 15 (-234)
。
这里normal
:
>>> dis.dis(normal)
9 0 SETUP_LOOP 44 (to 47)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_CONST 9 (10000000)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 30 (to 46)
16 STORE_FAST 0 (_)
10 19 LOAD_CONST 10 (12)
22 LOAD_CONST 5 (39)
25 BINARY_DIVIDE
26 LOAD_CONST 6 (2)
29 BINARY_MULTIPLY
30 LOAD_CONST 5 (39)
33 BINARY_DIVIDE
34 LOAD_CONST 7 (23)
37 BINARY_MULTIPLY
38 LOAD_CONST 8 (234)
41 BINARY_SUBTRACT
42 POP_TOP
43 JUMP_ABSOLUTE 13
>> 46 POP_BLOCK
>> 47 LOAD_CONST 0 (None)
50 RETURN_VALUE
这一次,计算只是部分简化(例如:省略了初始1 *
),大多数操作都是在运行时执行的。
看起来Python 2.7不会进行包含模糊/
运算符的常量折叠(可能是整数或浮点除法,具体取决于其操作数)。在程序顶部添加from __future__ import division
会导致常量在normal
中折叠,就像在floor
中一样(尽管结果当然不同,因为现在/
是浮动师。)
normal
10 0 SETUP_LOOP 24 (to 27)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_CONST 9 (10000000)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 10 (to 26)
16 STORE_FAST 0 (_)
11 19 LOAD_CONST 15 (-233.6370808678501)
22 POP_TOP
23 JUMP_ABSOLUTE 13
>> 26 POP_BLOCK
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE
它不像解释器无法使用默认的/
运算符进行常量折叠,但它没有。也许代码是从Python 3反向移植的,并且使它与模糊的除法运算符一起工作并不重要。
答案 1 :(得分:2)
您可以使用dis
module:
def floor():
12 // 39
def normal():
12 / 39
>>> dis.dis(floor)
2 0 LOAD_CONST 3 (0)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
>>> dis.dis(normal)
2 0 LOAD_CONST 1 (12)
3 LOAD_CONST 2 (39)
6 BINARY_DIVIDE
7 POP_TOP
8 LOAD_CONST 0 (None)
11 RETURN_VALUE
答案 2 :(得分:0)
"产生相同的结果"并不暗示"以同样的方式实施"。 另请注意,这些运营商并不总是产生与此处所述相同的结果:
Why Python's Integer Division Floors
因此,性能测量几乎取决于实现。 通常硬件浮点除法比整数除法要长。 可能是python经典除法(由你正常引用)是由硬件浮点除法实现的,并且只在最后阶段被截断为整数,而真正的除法(由你称为floored)是使用硬件int division实现的。快得多。