问题:while(1)vs. while(True)—为什么会有区别(在python 2字节码中)?
这个问题引起了有关perl中无限循环的问题:while(1)Vs。for(;;)是否存在速度差异?,我决定在python中运行类似的比较。我期望编译器会为while(True): pass
和生成相同的字节码while(1): pass
,但是python2.7实际上不是这种情况。
以下脚本:
import dis
def while_one():
while 1:
pass
def while_true():
while True:
pass
print("while 1")
print("----------------------------")
dis.dis(while_one)
print("while True")
print("----------------------------")
dis.dis(while_true)
产生以下结果:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 12 (to 15)
>> 3 LOAD_GLOBAL 0 (True)
6 JUMP_IF_FALSE 4 (to 13)
9 POP_TOP
9 10 JUMP_ABSOLUTE 3
>> 13 POP_TOP
14 POP_BLOCK
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
使用while True
明显更复杂。为什么是这样?
在其他情况下,python的行为就像True
等于1:
>>> True == 1
True
>>> True + True
2
为什么要while
区分两者?
我注意到python3确实使用相同的操作评估语句:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 3 (to 6)
9 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
python3中的布尔值评估方式是否有变化?
回答 0
在Python 2.x中,True
它不是关键字,而只是一个在类型中定义为1 的内置全局常量bool
。因此,解释器仍然必须加载的内容True
。换句话说,True
是可重新分配的:
Python 2.7 (r27:82508, Jul 3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
>>> True
4
在Python 3.x中,它实际上变成了关键字和实常数:
Python 3.1.2 (r312:79147, Jul 19 2010, 21:03:37)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
File "<stdin>", line 1
SyntaxError: assignment to keyword
因此,解释器可以将while True:
循环替换为无限循环。
回答 1
这不太正确
因此,解释器可以用无限循环代替while True:循环。
因为仍然可以打破循环。但是,确实如此的循环else
子句永远不会在Python 3中访问。而且,简化值查找使其与while 1
在Python 2中一样快运行,这也是事实。
性能比较
演示一个不平凡的while循环的时间差:
建立
def while1():
x = 0
while 1:
x += 1
if x == 10:
break
def whileTrue():
x = 0
while True:
x += 1
if x == 10:
break
Python 2
>>> import timeit
>>> min(timeit.repeat(while1))
0.49712109565734863
>>> min(timeit.repeat(whileTrue))
0.756627082824707
Python 3
>>> import timeit
>>> min(timeit.repeat(while1))
0.6462970309949014
>>> min(timeit.repeat(whileTrue))
0.6450748789939098
说明
为了解释差异,在Python 2中:
>>> import keyword
>>> 'True' in keyword.kwlist
False
但在Python 3中:
>>> import keyword
>>> 'True' in keyword.kwlist
True
>>> True = 'true?'
File "<stdin>", line 1
SyntaxError: can't assign to keyword
由于True
是Python 3中的关键字,因此解释程序不必查找该值即可查看是否有人用其他值替换了它。但是由于一个人可以赋值True
给另一个值,所以解释器每次都必须查找它。
Python 2总结
如果您在Python 2中有一个紧密而长期运行的循环,则可能应该使用while 1:
而不是while True:
。
Python 3总结
while True:
如果您没有打破循环的条件,请使用。
回答 2
这是一个已有7年历史的问题,已经有了一个不错的答案,但是这个问题的误解(任何一个答案都没有解决)使它可能会混淆其他一些标记为重复的问题。
在其他情况下,python的行为就好像True等于1:
>>> True == 1
True
>>> True + True
2
为什么同时区分两者?
实际上,while
这里根本没有做任何不同的事情。它区分1
,并True
以完全同样的方式,+
例如做。
这是2.7:
>>> dis.dis('True == 1')
1 0 LOAD_GLOBAL 0 (True)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 RETURN_VALUE
>>> dis.dis('True == 1')
1 0 LOAD_GLOBAL 0 (True)
3 LOAD_GLOBAL 0 (True)
6 BINARY_ADD
9 RETURN_VALUE
现在比较:
>>> dis.dis('1 + 1')
1 0 LOAD_CONST 1 (2)
3 RETURN_VALUE
它LOAD_GLOBAL (True)
为每个发出一个,True
优化器对全局没有任何作用。因此,while
区分1
并True
出于完全相同的原因+
。(并且==
不区分它们,因为优化器不会优化比较。)
现在比较3.6:
>>> dis.dis('True == 1')
1 0 LOAD_CONST 0 (True)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 RETURN_VALUE
>>> dis.dis('True + True')
1 0 LOAD_CONST 1 (2)
2 RETURN_VALUE
在这里,它LOAD_CONST (True)
为关键字发出一个,优化器可以利用它。因此,True + 1
不区分,出于完全相同的原因while True
。(并且==
仍然不能区分它们,因为优化器不会优化比较。)
同时,如果未对代码进行优化,则解释器最终将在所有这三种情况下进行处理,True
并且1
完全相同。bool
是的子类int
,并且从继承其大多数方法int
,并且True
内部整数值为1。因此,无论您要进行while
测试(__bool__
在3.x,__nonzero__
2.x中),比较(__eq__
)还是算术(__add__
),无论您使用True
还是,都在调用相同的方法1
。