为什么Python的FOR循环没有控制结构?

4
在Java中,我们可以使用以下方式来编写FOR循环:
for (i = 0; i < 10; i += 1) {

}

然而在 Python 中这是不可能的;FOR 只能以“foreach”的方式使用,循环遍历可迭代对象中的每个元素。

为什么在 Python 中省略了 FOR 循环的控制结构?


你可以使用类似于 xrange 的东西来完成相同的操作。 - Jesus Ramos
4个回答

8

Python之禅指出:“做一件事应该有且只有一种——最好是唯一——显而易见的方法。” Python已经有了这种方法:

for i in xrange(10):
    pass

如果你想要将所有的部分都明确地展示出来,也可以这样做:

for i in xrange(0, 10, 1):
    pass

因为已经有一种“显而易见”的方法来完成它,添加另一种方法会违反“禅”的原则。 (那是不是应该说“nez”?)

(注意:在Python 3中,请使用range代替xrange。)

C风格的for循环具有更多的灵活性,但最终你可以使用Python的while(或C语言的while)编写等效的循环,这不仅触及了“一个显而易见的方法”原则,还包括“简单比复杂好”等其他原则。当然,这都是品味问题,在这种情况下,是Guido van Rossum的品味。


1
而且 cython 足够聪明,可以将这些循环特殊处理为 C 风格的循环,而不需要 xrange 的开销。如果 pypy 也能识别它,我也不会感到惊讶。 - John La Rooy

3
由于这是一个关于Python 0.x的问题(事实上,很可能是其前身ABC的问题),只有Guido才能真正回答,而且仅当他记得时才行。你可以尝试请他在他的Python历史博客上写一篇文章。
然而,这里有一些很好的理由:
首先,只有单一形式的for而不是两种不同的形式可以使语言更小——对人类来说更容易学习和阅读,对计算机来说更容易解析。
没有“foreach”风格的for循环会导致许多差一错误,并使许多简单的代码变得更加冗长。
没有C-style的for循环会使一些已经非常复杂的for循环略微更加复杂,因为它们被迫成为while循环。这不影响像你这样的简单循环,可以写成“foreach”循环,例如for i in range(10):——更简洁、更可读,更难出错。
从这个角度看,选择显而易见。
*实际上,即使复杂的循环也可以通过迭代器转换为foreach循环,有时候这是一个好主意。例如,for (int i=2; i=next_prime(i); i<1000000)真的比for i in takewhile(lambda i:i<1000000, generate_primes()):更好吗?C++逐渐添加了功能,使后者成为可能,以避免你可能轻易犯下的错误...

1

通常情况下,迭代元素的性能更好。你可以通过以下方式获得相同的结果:

for i in xrange(0, 20):
    pass

你应该一定要阅读Python之禅: http://www.python.org/dev/peps/pep-0020/


0

因为它只是一个 while 循环的语法糖

i = 0
while i < 10:
    # stuff
    i += 1

如果你在C风格的for循环中从未遇到过一次偏移错误,请举手。我知道你没有。


嗯,foreach循环也只是语法糖而已,它实际上是一个while循环(http://pastebin.com/S9AqxGMJ),但仍然值得拥有... - abarnert
1
一个C风格的for循环并不是那个特定的while循环的语法糖,因为如果你在C风格的for循环中使用continue,那么继续执行的代码i += 1会被执行。但在那个while循环中则不然。在这种情况下,“显而易见”的解决方法是将i += 1放在循环开始处,将i = 0改为i = -1,将i < 10改为i < 9,但是尝试编写完全等效于C风格for循环的代码可能会有些混乱 :-) - Steve Jessop
@SteveJessop,你说得对。我的回答过于简单了。你也不能轻松地处理在while表达式中执行赋值的循环。我会把它归咎于我试图进行防御性编程并尽可能避免复杂的C循环的习惯。 - John La Rooy
如果我需要做一些太复杂的事情,无法简单地使用forwhilewhile True: … break …翻译时,我会将复杂的部分放在生成器表达式中(或者是itertools调用或其他方式),然后它就变成了一个明显的for循环,其中breakcontinue的含义与您想要的完全相同... - abarnert
@abarnert,这是一个很好的练习,因为如果生成器很复杂,你可以对其进行单元测试。 - John La Rooy
@gnibbler: 是的,你可以通过执行 my_generator = list(my_generator); print(my_generator, file=stderr) 来进行打印调试。当然,有时候你会忘记你的迭代器有多大,从而淹没控制台甚至导致交换机崩溃,使你的计算机陷入停滞……但是当你不那么愚蠢时,能够这样做还是很好的。 :) - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接