python数值交换不推荐使用中间值,使用Pythonic的实现不仅简洁,而且执行效率高。
中间值方法
交换两个变量的值,我们熟悉的方法如下:1
2
3temp = x
x = y
y = temp
Pythonic 实现方式
python中有Pythonic的实现方式:1
x, y = y, x
交换效率
我们使用timeit查看下两则的交换效率1
2
3
4
5 > from timeit import Timer
"x, y = y, x", "x=2;y=3").timeit() > Timer(
0.051779985427856445
"temp=x;x=y;y=temp", "x=2; y=3").timeit() > Timer(
0.06303882598876953
可以看到Pythonic的实现不仅简洁,而且执行效率高
dis分析
使用dis分析python执行的字节码:1
2
3
4
5
6
7
8
9
10
11
12
13import dis
def swap1():
x, y = 2, 3
x, y = y, x
def swap2():
x, y = 2, 3
temp = x
x = y
y = temp
dis.dis(swap1)
dis.dis(swap2)
结果分别如下:1
2
3
4
5
6
7
8
9
10
11
12
13>>> dis.dis(swap1)
2 0 LOAD_CONST 3 ((2, 3))
3 UNPACK_SEQUENCE 2
6 STORE_FAST 0 (x)
9 STORE_FAST 1 (y)
3 12 LOAD_FAST 1 (y)
15 LOAD_FAST 0 (x)
18 ROT_TWO
19 STORE_FAST 0 (x)
22 STORE_FAST 1 (y)
25 LOAD_CONST 0 (None)
28 RETURN_VALUE
1 | >>> dis.dis(swap2) |
通过字节码可以看出:swap1使用了ROT_TWO指令,而swap2比swap1多执行了一个LOAD_FAST+STORE_FAST(入栈和赋值)。
那么ROT_TWO做了什么事情,使得变量能够成功交换,且比LOAD_FAST+STORE_FAST效率高呢?
查看官方api,它的作用是交换栈顶的两个元素:1
2ROT_TWO()
Swaps the two top-most stack items.
而ROT_TWO在cpython的实现如下:1
2
3
4
5
6
7TARGET(ROT_TWO) {
PyObject *top = TOP();
PyObject *second = SECOND();
SET_TOP(second);
SET_SECOND(top);
FAST_DISPATCH();
}
SET_TOP和SET_SECOND的定义:1
2#define SET_TOP(v) (stack_pointer[-1] = (v))
#define SET_SECOND(v) (stack_pointer[-2] = (v))
栈存放的是对象的指针,那么x,y=y,x所做的就是将栈顶的两个指针互换了一下,从而实现了x和y值的交换。而直接使用指针进行交换,就是其为什么执行速度会更快了。