关于perl:while (1) Vs. for (;;) Is there a speed difference?中关于无限循环的这个问题,我决定在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 :(得分:120)
在Python 2.x中,True
不是关键字,只是在bool
类型中定义为1的built-in global constant。因此,解释器仍然必须加载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 it truly becomes a keyword和一个实常数:
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 :(得分:12)
这不太正确,
因此解释器可以用无限循环替换while True:循环。
因为人们仍然可以摆脱循环。但确实在Python 3中永远不会访问这样一个循环的else
子句。简化值查找也使得它的运行速度与Python中的while 1
一样快。 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
>>> import timeit
>>> min(timeit.repeat(while1))
0.49712109565734863
>>> min(timeit.repeat(whileTrue))
0.756627082824707
>>> 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中有一个紧凑,长时间运行的循环,你可能应该使用while 1:
而不是while True:
。
如果您没有条件退出循环,请使用while True:
。
答案 2 :(得分:3)
这是一个已有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
测试(3.x中的__bool__
,2.x中的__nonzero__
),比较(__eq__
)或算术(__add__
),你'无论您使用True
还是1
,都要调用相同的方法。