今天看到一个帖子说 python 中 while 1: pass 要比 while True: pass 速度更快。
第一感觉是有点反直觉。 while 1: pass 貌似应等价于 while bool(1): pass , 怎么也要比 while True: pass 多一次转换的调用。
于是做了一个简单的实验,
In [1]: timeit while True: break
10000000 loops, best of 3: 109 ns per loop
In [2]: timeit while 1: break
10000000 loops, best of 3: 54.2 ns per loop
while 1: pass 比 while True: pass 快了近一倍。看来是对所谓的 bool 转换的的理解有误,需要在字节码级别一探究竟。
In [3]: def foo():
...: while 1:
...: break
In [6]: dis.dis(foo)
2 0 SETUP_LOOP 4 (to 7)
3 >> 3 BREAK_LOOP
4 JUMP_ABSOLUTE 3
>> 7 LOAD_CONST 0 (None)
10 RETURN_VALUE
In [7]: def foo():
while True:
break
...:
In [8]: dis.dis(foo)
2 0 SETUP_LOOP 11 (to 14)
>> 3 LOAD_GLOBAL 0 (True)
6 POP_JUMP_IF_FALSE 13
3 9 BREAK_LOOP
10 JUMP_ABSOLUTE 3
>> 13 POP_BLOCK
>> 14 LOAD_CONST 0 (None)
17 RETURN_VALUE
用 dis 模块做一下反编译, 两者的区别就很明显了。 while 1: 实际上被编译器完全优化掉了, 而 while True: 则需要 load 一个全局变量 True 后再做一次 test 。True 和 False 虽然在很多 IDE 或 Editor 里面都被高亮为常量 :),但在 python 里并不是 Literal , 只是 builtin 里两个类型为 bool 的普通全局变量而已。 虽然 True = 0 很愚蠢, 但没人可以阻止你这样做。
最后附上一些 python 操作的字节码,算是对一些常见 python 操作效率区别的解释吧。
In [21]: def swap(x, y):
....: temp = x
....: x = y
....: y = temp
....:
In [22]: dis.dis(swap)
2 0 LOAD_FAST 0 (x)
3 STORE_FAST 2 (temp)
3 6 LOAD_FAST 1 (y)
9 STORE_FAST 0 (x)
4 12 LOAD_FAST 2 (temp)
15 STORE_FAST 1 (y)
18 LOAD_CONST 0 (None)
21 RETURN_VALUE
In [19]: def swap(x, y):
x, y = y, x
....:
In [20]: dis.dis(swap)
2 0 LOAD_FAST 1 (y)
3 LOAD_FAST 0 (x)
6 ROT_TWO
7 STORE_FAST 0 (x)
10 STORE_FAST 1 (y)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
In [23]: def swap(x, y, z):
x, y, z = y, z, x
....:
In [24]: dis.dis(swap)
2 0 LOAD_FAST 1 (y)
3 LOAD_FAST 2 (z)
6 LOAD_FAST 0 (x)
9 ROT_THREE
10 ROT_TWO
11 STORE_FAST 0 (x)
14 STORE_FAST 1 (y)
17 STORE_FAST 2 (z)
20 LOAD_CONST 0 (None)
23 RETURN_VALUE
In [25]: def swap(a, b, c, d):
a, b, c, d = b, c, d, a
....:
In [26]: dis.dis(swap)
2 0 LOAD_FAST 1 (b)
3 LOAD_FAST 2 (c)
6 LOAD_FAST 3 (d)
9 LOAD_FAST 0 (a)
12 BUILD_TUPLE 4
15 UNPACK_SEQUENCE 4
18 STORE_FAST 0 (a)
21 STORE_FAST 1 (b)
24 STORE_FAST 2 (c)
27 STORE_FAST 3 (d)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE