1. 问题背景
在 Python 中,我们可以通过 += 和 = … + 完成累加操作,在实际开发过程中我们一般会优先选择 +=,然而最近在对比 += 和 = … + 的性能时出现了 += 反而更慢的现象。因此,我们决定对此问题进行深入探讨。
2. 解决方案
为了准确地评估 += 和 = … + 的性能差异,我们编写了一个简单的测试脚本,封装了两个函数并使用 timeit 测试模块来测量它们的执行时间。
def testAccumPlusEqual():x = 0for i in range(100):x += 1return xdef testAccumEqualPlus():x = 0for i in range(100):x = x + 1return xif __name__ == '__main__':import timeitprint(timeit.repeat("testAccumPlusEqual()",setup="from __main__ import testAccumPlusEqual"))print(timeit.repeat("testAccumEqualPlus()",setup="from __main__ import testAccumEqualPlus"))
测试结果显示,在我们的测试环境下,= … + 比 += 的执行速度更快。为了进一步探究原因,我们使用 dis 模块来查看这两个函数的字节码:
>>> import dis
>>> dis.dis(testAccumEqualPlus)2 0 LOAD_CONST 1 (0)3 STORE_FAST 0 (x)3 6 SETUP_LOOP 30 (to 39)9 LOAD_GLOBAL 0 (range)12 LOAD_CONST 2 (100)15 CALL_FUNCTION 118 GET_ITER >> 19 FOR_ITER 16 (to 38)22 STORE_FAST 1 (i)4 25 LOAD_FAST 0 (x)28 LOAD_CONST 3 (1)31 BINARY_ADD 32 STORE_FAST 0 (x)35 JUMP_ABSOLUTE 19>> 38 POP_BLOCK 5 >> 39 LOAD_FAST 0 (x)42 RETURN_VALUE
>>> dis.dis(testAccumPlusEqual)2 0 LOAD_CONST 1 (0)3 STORE_FAST 0 (x)3 6 SETUP_LOOP 30 (to 39)9 LOAD_GLOBAL 0 (range)12 LOAD_CONST 2 (100)15 CALL_FUNCTION 118 GET_ITER >> 19 FOR_ITER 16 (to 38)22 STORE_FAST 1 (i)4 25 LOAD_FAST 0 (x)28 LOAD_CONST 3 (1)31 INPLACE_ADD 32 STORE_FAST 0 (x)35 JUMP_ABSOLUTE 19>> 38 POP_BLOCK 5 >> 39 LOAD_FAST 0 (x)42 RETURN_VALUE
结果表明,+= 使用 INPLACE_ADD 指令,而 = … + 使用 BINARY_ADD 指令。两者之间的区别在于,INPLACE_ADD 会直接修改操作数的值,而 BINARY_ADD 则会创建一个新的对象。因此,+= 操作需要花费更多的时间来更新操作数的值。
综合以上分析,我们可以得出结论,在 Python 中,= … + 比 += 的执行速度更快,原因在于 += 使用 INPLACE_ADD 指令,直接修改操作数的值,而 = … + 使用 BINARY_ADD 指令,创建一个新的对象。