Python while语句的其他子句


321

我注意到以下代码在Python中是合法的。我的问题是为什么?是否有特定原因?

n = 5
while n != 0:
    print n
    n -= 1
else:
    print "what the..."

5
@detly:这是因为大多数人都避免使用此构造。:)我相信Guido在Py3k流程中提到,至少else为此选择单词是一个非常糟糕的主意,他们不会再做这些了。
尼古拉斯·奈特

5
@尼古拉斯·奈特(Nicholas Knight)-是的,虽然很诱人,但可能只有我乍一看才知道。任何其他可怜的汁液都必须去看看语言规格,或者及时回到那里,在Staheeeeey上发表一个问题...
有意思的是,2010年

8
选择“其他”的想法是,该构造通常与while循环中的“ if X:break”结合使用。由于如果不中断循环就会执行“ else”子句,因此它对“ if”形成了一种“ else”排序。
乔纳森·哈特利

12
他们应该重命名它after:
naught101 '16

Answers:


388

else仅当您的while条件为假时才执行该子句。如果您break超出循环范围,或者引发了异常,则不会执行该异常。

考虑它的一种方法是关于条件的if / else构造:

if condition:
    handle_true()
else:
    handle_false()

与循环构造类似:

while condition:
    handle_true()
else:
    # condition is false now, handle and go on with the rest of the program
    handle_false()

一个示例可能类似于:

while value < threshold:
    if not process_acceptable_value(value):
        # something went wrong, exit the loop; don't pass go, don't collect 200
        break
    value = update(value)
else:
    # value >= threshold; pass go, collect 200
    handle_threshold_reached()

42
“只有当您的while条件变为false时,才执行else子句。” 这里的用语意味着您的while状态从true变为false,然后其他状态将被执行。但是,如果while永远都不为真,则else子句仍将执行。
2014年

所以纠正我,如果我错了,但这是完全一样的while {} something ,除了something会,如果你被跳过breakwhile循环。
丹尼尔·卡普兰

2
也许最精确的伪代码是:while(True){if(cond){handle_true(); }其他{handle_false(); 打破; }
VinGarcia '16

2
“不要过去,不要收集200”,哈哈,每个知道这是哪里的人都有一个美好的童年
Stefan Octavian

102

else如果您通过退出循环条件或掉落try块的底部来正常退出一个块,则执行该子句。它执行,如果你break还是return一个块外,或引发异常。它不仅适用于while和for循环,还可以尝试块。

您通常会在通常会提前退出循环的地方找到它,而在循环结束时运行是意外/异常的情况。例如,如果要遍历列表以查找值:

for value in values:
    if value == 5:
        print "Found it!"
        break
else:
    print "Nowhere to be found. :-("

1
实际上,这是一个相当有用的构造。不知道我found_it=False在循环开始时输入了多少次,然后在循环found_it结束时进行了一次if检查
Cruncher

42

作为对的答复Is there a specific reason?,这是一个有趣的应用程序:突破了多个循环级别。

它是这样工作的:外循环在结尾处有一个中断,因此只能执行一次。但是,如果内部循环完成(未找到除数),那么它将到达else语句,并且永远不会到达外部中断。这样,内部循环中的中断将打破两个循环,而不仅仅是一个循环。

for k in [2, 3, 5, 7, 11, 13, 17, 25]:
    for m in range(2, 10):
        if k == m:
            continue
        print 'trying %s %% %s' % (k, m)
        if k % m == 0:
            print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
            break
    else:
        continue
    print 'breaking another level of loop'
    break
else:
    print 'no divisor could be found!'

对于whilefor循环else,除非break已使用,否则该语句将在最后执行。

在大多数情况下,有更好的方法可以做到这一点(将其包装到函数中或引发异常),但这是可行的!


1
我没有投票,但我想我知道为什么有人这样做。您没有回答问题,而是提供了14行代码,仅包含2行描述。如果与所问的问题相关,您不是在告诉我们...
BlueEel 2014年

1
@BlueEel感谢您的反馈!我添加了有关代码的更多解释,并使其更清楚地回答了问题(因为它确实回答了部分问题)。
2014年

您设法将代码放在上下文中,尽管您没有回答所有问题,但我现在看到了相关性。我赞成您的回答,因为它对新手和新手(就python而言,对我自己来说)非常有用。-谢谢,我学到了一些东西。
BlueEel 2014年

我喜欢简单的应用程序-现在,我明白了为什么有人会使用它。虽然我从未见过需要它。
gabe 2015年

该示例显示了for / else 的用法,但问题专门关于while / else。
伊恩·戈德比

20

当while条件评估为false时,将执行else子句。

文档中

只要表达式为真,while语句将用于重复执行:

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

这将反复测试表达式,如果为true,则执行第一个套件;否则,将执行第一个套件。如果表达式为假(可能是第一次测试)else,则执行该子句的套件(如果存在),并终止循环。

break在第一个套件中执行的语句将终止循环,而不执行该else子句的套件。continue在第一个套件中执行的语句将跳过套件的其余部分,然后返回测试表达式。


15

我的回答将集中于何时可以使用while / for-else。

乍一看,使用时似乎没有什么不同

while CONDITION:
    EXPRESSIONS
print 'ELSE'
print 'The next statement'

while CONDITION:
    EXPRESSIONS
else:
    print 'ELSE'
print 'The next statement'

因为该print 'ELSE'语句似乎总是在两种情况下都执行(无论是在while循环结束还是未运行时)。

然后,仅在print 'ELSE'不执行该语句时有所不同。这是break在下面的代码块中while

In [17]: i = 0

In [18]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
else:
    print 'ELSE'
print 'The next statement'
   ....:
0
1
2
The next statement

如果不同于:

In [19]: i = 0

In [20]: while i < 5:
    print i
    if i == 2:
        break
    i = i +1
print 'ELSE'
print 'The next statement'
   ....:
0
1
2
ELSE
The next statement

return 不在此类别中,因为它对以上两种情况具有相同的效果。

异常引发也不会引起差异,因为引发异常时,将在异常处理程序(块除外)中执行下一个代码的位置,将不会执行else子句中或while子句之后的代码。


4

我知道这是个老问题,但是...

就像Raymond Hettinger所说的那样,应该调用它while/no_break而不是while/else
如果您查看此摘要,我会很容易理解不足。

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
if n == 0:
    print n

现在,我们无需在while循环后检查条件,而是可以将其交换else并摆脱该检查。

n = 5
while n > 0:
    print n
    n -= 1
    if n == 2:
        break
else:  # read it as "no_break"
    print n

我一直读它是while/no_break为了理解代码,而语法对我来说更有意义。


3

else子句仅在while条件变为false 时执行。

这里有些例子:

示例1:最初条件为假,因此执行else子句

i = 99999999

while i < 5:
    print(i)
    i += 1
else:
    print('this')

输出:

this

例2:同时条件 i < 5从来没有成为因为假i == 3突破的循环,所以else从句未执行。

i = 0

while i < 5:
    print(i)
    if i == 3:
        break
    i += 1
else:
    print('this')

输出:

0
1
2
3

实施例3:而条件 i < 5成为当假i5,所以else从句被执行。

i = 0

while i < 5:
    print(i)
    i += 1
else:
    print('this')

输出:

0
1
2
3
4
this

0

else:仅当while循环不再满足其条件时才执行该语句(在您的示例中,当n != 0false时)。

所以输出是这样的:

5
4
3
2
1
what the...

我知道,但是这种while / else在Java中不起作用。当我发现它可以在Python中工作时,我发现它很有趣。我只是好奇,想知道技术原因。
伊万

6
@Ivan:并不是说它在Java中不起作用,而是在Java中不存在。如果有人愿意将其添加到语言中,则可以使其工作。
伊格纳西奥·巴斯克斯

1
不,虽然为False:.. else ..仍然运行else子句。准确地说:else仅在中断循环时才运行。
Leo Ufimtsev '19

0

如果while循环未中断,则执行Else。

我有点想用“跑步者”隐喻来思考它。

“其他”就像越过终点线,与您是从曲目的开头还是结尾开始无关。“其他人”只是,如果你在两者之间的某处破裂执行。

runner_at = 0 # or 10 makes no difference, if unlucky_sector is not 0-10
unlucky_sector = 6
while runner_at < 10:
    print("Runner at: ", runner_at)
    if runner_at == unlucky_sector:
        print("Runner fell and broke his foot. Will not reach finish.")
        break
    runner_at += 1
else:
    print("Runner has finished the race!") # Not executed if runner broke his foot.

主要用例是使用这种脱离嵌套循环的方式,或者仅在循环未在某个地方中断的情况下才想运行某些语句(认为中断是一种不寻常的情况)。

例如,以下是关于如何不使用变量或不尝试/不抓住而跳出内部循环的机制:

for i in [1,2,3]:
    for j in ['a', 'unlucky', 'c']:
        print(i, j)
        if j == 'unlucky':
            break
    else: 
        continue  # Only executed if inner loop didn't break.
    break         # This is only reached if inner loop 'breaked' out since continue didn't run. 

print("Finished")
# 1 a
# 1 b
# Finished

-1

在Python中更好地使用“ while:else:”构造应该是:如果在“ while”中没有执行循环,则执行“ else”语句。今天的工作方式没有意义,因为您可以使用下面的代码获得相同的结果...

n = 5
while n != 0:
    print n
    n -= 1
print "what the..."

8
不,不同之处在于,else如果您使用breakreturn关键字退出循环,则不会执行该块。在您的示例中,print如果循环在break命令中结束,也将执行。
notsurewhattodo

2
您描述的是大多数人希望功能起作用的方式,而不是功能的实际作用!
dotancohen '16

-2

这对于社交互动很有用。

while (Date != "January 1st"):
    time.sleep(1)
else:
    print("Happy new year!")

2
else此处的目的到底是什么?没有它,代码的作用完全相同。
wovano

如果break倒计时期间的时钟和日历不使用,else则会说“新年快乐!”。瞬间没有任何意义。
Guimoute

@Guimote,“如果您的时钟和日历break” 是什么意思?break代码中没有。
wovano
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.