我已经看到了两种在Python中创建无限循环的方法:
while 1:
do_something()
while True:
do_something()
这些之间有什么区别吗? 一个比另一个更pythonic吗?
也许无限循环不是pythonic吗? (请参阅balpha)
从根本上讲,这并不重要,这样的细节并不会真正影响某些东西是否为" pythonic"。
但是,如果您对琐事感兴趣,则有一些区别。
内置的布尔类型直到Python 2.3才存在,因此原本打算在较早版本上运行的代码倾向于使用while 1:形式。例如,您将在标准库中看到它。
True和False内置不是Python 3之前的保留字,因此可以分配给它们,以更改其值。这对上述情况有帮助,因为代码可以做到True = 1以实现向后兼容,但是这意味着每次使用全局名称字典时都需要在全局字典中查找名称True。
由于上述限制,两个版本编译的字节码在Python 2中是不同的,因为存在对不能用于True的常量整数的优化。因为Python可以在编译1时告诉它始终非零,所以它消除了条件跳转,并且根本不加载常量:
>>> import dis
>>> def while_1():
... while 1:
... pass
...
>>> def while_true():
... while True:
... pass
...
>>> dis.dis(while_1)
2 0 SETUP_LOOP 5 (to 8)
3 >> 3 JUMP_ABSOLUTE 3
6 POP_TOP
7 POP_BLOCK
>> 8 LOAD_CONST 0 (None)
11 RETURN_VALUE
>>> dis.dis(while_true)
2 0 SETUP_LOOP 12 (to 15)
>> 3 LOAD_GLOBAL 0 (True)
6 JUMP_IF_FALSE 4 (to 13)
9 POP_TOP
3 10 JUMP_ABSOLUTE 3
>> 13 POP_TOP
14 POP_BLOCK
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
因此,while True:稍微易于阅读,而while 1:对旧版本的Python则有点友善。由于这些天您不太可能需要在Python 2.2上运行,也不必担心循环的字节码计数,因此前者在某种程度上是可取的。
+1:很好的解释了为什么问题应该降到零以下。
我想指出的是,以我的拙见,做某事的最Python方式是不要为这样的细节烦恼。尽管该帖子绝对有趣且内容丰富,但我对此表示赞赏,但我坚持认为while True:更具Python风格。至少以我解释pythonic奇数词的方式,您的学习成绩可能会有所不同。
刚尝试做True = False,效果"如预期",有趣:)
如果您非常努力,仍可以在3.x中重新定义True。在3.0中,import builtins; builtins.__dict__[True] = 0可以做到;在3.3中,您必须有更多的创造力,但仍然有可能。如果情况变得更糟,您始终可以ctypes进入C API(或与其他实现等效)。有趣的是,编译器假定您无法做到,因此某些表达式将被编译出来,而另一些表达式将以实现/版本相关的方式使用您的新值。而且,如果您能很好地利用所有这些资源,则可能会找到更好的时间利用方式...
最Python的方式将永远是最易读的。使用while True:
对于C程序员而言,最易读的是1:。
" while 1:"与" for(;;)" :-)完全不同
@nomemory:问题是关于" Pythonic"的,它与C程序员几乎没有关系。如果您希望C程序员能读懂某些东西,请使用C。
@ S.Lott:我想说的是可读性是非常相对的。
没关系。两者都不难理解,尽管我个人总是使用while True,这更加明确。
更一般而言,人们用Python编写的很多while-break循环可能是另一回事。有时我看到人们写i = 0; while True: i += 1 ...,可以用for i in itertools.count()代替,而人们写while True: foo = fun() if foo is None: break时,可以写成for foo in iter(fun, None),这需要学习,但需要更少的样板,也没有机会犯傻。
都不行
它们都意味着我必须扫描代码以查找break,而不是能够在其所属位置看到停止条件。
我尝试尽可能避免这种情况,如果不可能,请让代码这样说:
while not found_answer:
check_number += 1
if check_number == 42:
found_answer = True
编辑:似乎上面的"避免"一词不够清楚。通常应该完全避免使用基本上无限的循环并将其从循环内的某个位置放置(使用break)。有时这是不可能的。在那种情况下,我喜欢使用类似上面的代码的东西,但是,它仍然表示相同的概念,上面的代码不过是一种折衷,但是至少,我可以像我一样在开始时就说明循环的目的不会调用函数do_something_with_args(*args)。
但是在您的代码中,您只需扫描代码中的found_answer = True。
我不认为这是可取的。通常使用break的原因是无法轻松或有效地表达停止条件。如果从字面上讲是使用像found_answer这样的变量,则必须扫描该变量而不是break-通常,您仍然需要continue而不是break才能使其退出循环。
@迈克·格雷厄姆:是的,我说我想完全避免这种情况。如果使用它,我会通过给布尔值一个名称来解释该循环停止的原因来使事情变得清晰(即可读)。
@Scott Griffiths:但是与True不同,not found_answer或not received_quit_command向代码读者讲了一些内容。
@balpha:那是一个公平的观点,但是当您真正需要的只是开始时的简单注释时,您不禁要引入一个新变量并添加一个额外的条件评估,以使循环的意图更加清楚,我感到不解。
@Scott Griffiths:...以及在break语句中。但是,是的,这可能是个问题。我喜欢在可能的地方使用函数和变量名作为"注释"。但是你的观点是正确的。无论如何,我的观点还是尝试做完全不同的事情。我真的不明白为什么我的答案不清楚。
如果您有一种算法可以在有限时间内终止,那么我建议您这样做,它总是比while True更安全:
maxiter = 1000
for i in xrange(maxiter):
# your code
# on success:
break
else:
# that algorithm has not finished in maxiter steps! do something accordingly
我在这方面不同意,并且有一所杰出的学校制定尽可能严格的标准。如果期望值是零,那么说" == 0"并且不要依赖" <= 1",因为为-1可能表示之前处理的完全非预期分支;否则,则为0。肯定会检测到一个无限循环,而其他代码仍然必须确保这一点。
IMO的第二种选择更为明显。
如果您可以摆脱while并编写更紧凑的代码,那可能更像pythonic。
例如:
# Get the even numbers in the range 1..10
# Version 1
l = []
n = 1
while 1:
if n % 2 == 0: l.append(n)
n += 1
if n > 10: break
print l
# Version 2
print [i for i in range(1, 11) if i % 2 == 0]
# Version 3
print range(2, 11, 2)
第一个版本也可以在尚未定义True的早期版本中使用。
在这一点上,为Python 3编程之后,无论如何仍然要保持向后兼容性。
我不知道哪个是不支持True的Python的最新版本?
我认为这主要是风格问题。两者都应该很容易理解为无限循环。
但是,我个人更喜欢第二种选择。这是因为它只需要花很少的时间就能理解,特别是对于没有C背景的程序员而言。
我相信第二个表达式更明确,因此更Python化。
更好的方法是"有条件时退出循环"时为"真"。
这只是样式问题,任何编程初学者都可以理解这两种选择。
但是,第二个选项仅在未将True分配给False的情况下才有效,这在Python 3之前是可行的:
>>> True = False
>>> True
False
那是一个很好的观察,但是与其他开发人员一起在项目上执行此操作的任何人几乎肯定会被打败他们一生。
是的,这当然只是玩笑。
更多推荐
python里while 1是什么意思_关于python:“ while 1”和“ while True”之间有什么区别?...
发布评论