Python while 语句上的 Else 子句

Else clause on Python while statement

提问人:Ivan 提问时间:7/21/2010 最后编辑:Karl KnechtelIvan 更新时间:6/28/2023 访问量:258402

问:

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

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

许多初学者在尝试将 if/else 块放入 a afor 循环中时,不小心偶然发现了这种语法,并且没有正确缩进 else解决方案是确保 else 块与 if 对齐,假设您打算将它们配对。这个问题解释了为什么它没有导致语法错误,以及生成的代码意味着什么。另请参阅我收到 IndentationError。我该如何修复它?,对于报告语法错误的情况。

参见 为什么 python 在 for 和 while 循环之后使用“else”? 有关如何充分利用该功能的问题。

python 语法 while-loop if-statement

评论

13赞 Nicholas Knight 7/21/2010
@detly:那是因为大多数人都避免这种结构。:)我相信 Guido 在 Py3k 过程中提到过,至少,选择这个词来表示这种用法是一个非常糟糕的主意,他们不会再这样做了。else
6赞 detly 7/21/2010
@Nicholas骑士 - 是的,虽然很诱人,但可能只有我第一眼才明白。任何其他可怜的 sap 都必须去看看语言规范,或者回到过去并在 Sta- heeeeeey 上发布一个问题......
9赞 Jonathan Hartley 11/22/2013
选择“else”背后的想法是,这个结构应该经常与while循环中的“if X: break”结合使用。由于如果我们不跳出循环,就会执行“else”子句,因此它形成了“if”的某种“else”。
21赞 naught101 3/15/2016
他们应该重命名它.after:
6赞 AusIV 6/21/2016
@naught101 - After 也不是很合适,因为如果您使用 “break” 或 “return” 退出循环,它就不会执行。我总是告诉那些正在努力记住用法的人,“如果你要打破循环,你就有机会在你的中断语句之前做一些事情。如果你正在耗尽你的集合(在 for 循环中)或破坏你的循环条件(在 while 循环中),'else' 子句就是你要结束的地方。

答:

479赞 ars 7/21/2010 #1

仅当条件变为 false 时,才会执行该子句。如果退出循环,或者引发异常,则不会执行该异常。elsewhilebreak

一种考虑方式是将其视为与条件相关的 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()

评论

75赞 user597608 10/11/2014
“else 子句仅在 while 条件变为 false 时执行。”这里的措辞意味着你的 while 状态从 true 变为 false 状态,并且 else 将被执行。但是,如果 while 从不为真,则仍将执行 else 子句。
2赞 Daniel Kaplan 3/19/2015
伪代码所以如果我错了,请纠正我,但这与完全相同,只是如果您在循环中,将被跳过。while {} somethingsomethingbreakwhile
2赞 VinGarcia 12/5/2016
也许最精确的伪代码是: while(True) { if (cond) { handle_true(); } else { handle_false(); break; } }
1赞 starriet 8/5/2020
如果 while 循环以 'break' 结束,即使 while 条件变为 false,也不会执行 else 子句。例如,在中断之前将条件更改为 false。
1赞 chepner 1/22/2023
如果执行,则条件的计算结果从未为 false。(如果再次达到条件,上下文可能会变得这样,条件的计算结果为 false,但这与计算结果为 false 不同。break
30赞 Mark Rushakoff 7/21/2010 #2

当 while 条件的计算结果为 false 时,将执行 else-子句。

文档中:

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

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

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

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

-1赞 BoltClock 7/21/2010 #3

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

因此,输出将是这样的:

5
4
3
2
1
what the...

评论

0赞 Ivan 7/21/2010
我知道,但这种while/else在Java中不起作用。当我发现它在 Python 中工作时,我发现它很有趣。我只是好奇,想知道技术原因。
7赞 Ignacio Vazquez-Abrams 7/21/2010
@Ivan:与其说它在 Java 中不起作用,不如说它在 Java 中不存在。如果有人愿意将它添加到语言中,它可以工作。
1赞 Leo Ufimtsev 7/29/2019
否,而 False: ..还。。仍然运行 else 子句。更准确地说:else 只有在循环被打破时才不运行。
0赞 John 12/5/2021
如果出现异常或异常,也不会运行该部件。elsereturn
140赞 John Kugelman 7/21/2010 #4

如果您通过击中循环条件或从尝试块的底部掉下来正常退出块,则执行该子句。如果您或退出区块,则不会执行它,或者引发异常。它不仅适用于 while 和 for 循环,还适用于 try 块。elsebreakreturn

你通常会在通常提前退出循环的地方找到它,而从循环的末端跑出去是一个意外/不寻常的情况。例如,如果要循环浏览列表以查找值:

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

评论

5赞 Cruncher 2/20/2020
对于这样的事情,实际上是一个相当有用的结构。不知道我在循环开始时放了多少次,然后在最后做了一个 if 检查found_it=Falsefound_it
0赞 Eyal 9/9/2023
这比上面说的“else 子句仅在 while 条件变为 false 时执行”是一个更好的解释。如果 while 条件变为 false,但在循环之前调用 “break”,则不会调用 else 子句。while 条件变为 false 是不够的,您还必须执行该条件。
-2赞 Jean Ferri 5/24/2013 #5

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

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

评论

10赞 notsurewhattodo 10/22/2013
不,区别在于,如果您使用 or 关键字离开循环,则不会执行该块。在您的示例中,如果循环在命令上结束,也将执行。elsebreakreturnprintbreak
4赞 dotancohen 2/29/2016
你描述的是大多数人希望这个功能如何工作,而不是它的实际工作方式!
43赞 Mark 6/8/2014 #6

请允许我举个例子来说明为什么使用这个 -子句。但:else

  • 我的观点现在在Leo的回答中得到了更好的解释
  • 我使用 - 而不是 -loop,但工作方式类似(除非遇到中断,否则执行)forwhileelse
  • 有更好的方法可以做到这一点(例如,将其包装到函数中或引发异常)
突破多级循环

它是这样工作的:外部循环的末尾有一个中断,所以它只会执行一次。但是,如果内部循环完成(找不到除数),则它到达 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!'
23赞 HVNSweeting 10/24/2014 #7

我的答案将集中在我们何时可以使用 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' 不会被执行时,情况才会有所不同。 这是当代码块内部出现中断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不属于此类别,因为它对上述两种情况具有相同的效果。

异常引发也不会造成差异,因为当它引发时,下一个代码将被执行的位置是在异常处理程序中(除了块),子句中的代码或子句之后的代码将不会被执行。elsewhile

2赞 Leo Ufimtsev 7/29/2019 #8

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

我有点喜欢用“跑步者”的比喻来思考它。

“其他”就像越过终点线,与你是从赛道的起点还是终点开始无关。“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.

主要用例是使用这种断开嵌套循环的方法,或者如果你只想在循环没有在某处断开时运行一些语句(认为断开是一种不寻常的情况)。

例如,以下是关于如何在不使用变量或 try/catch 的情况下跳出内部循环的机制:

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
13赞 Iluvatar 8/7/2019 #9

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

正如雷蒙德·赫廷格(Raymond Hettinger)所说,应该将其称为而不是.
如果你看这个片段,我发现很容易理解。
while/no_breakwhile/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

25赞 Saif 12/27/2019 #10

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

以下是一些示例:

示例 1:最初条件为 false,因此执行 else-clause

i = 99999999

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

输出:

this

示例 2:while 条件永远不会变成 false,因为会破坏循环,因此没有执行 else-clausei < 5i == 3

i = 0

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

输出:

0
1
2
3

示例 3:while条件在 was 时变为 false,因此执行了 else-clausei < 5i5

i = 0

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

输出:

0
1
2
3
4
this
-2赞 Mansour.M 8/28/2020 #11

据我所知,在任何语言中向循环添加 else 的主要原因是在迭代器不在您的控制范围内的情况下。想象一下,迭代器在服务器上,你只需给它一个信号来获取接下来的 100 条数据记录。只要接收的数据长度为 100,您就希望循环继续进行。如果它更少,你需要它再去一次,然后结束它。在许多其他情况下,您无法控制上次迭代。在这些情况下,可以选择添加其他选项会使一切变得更加容易。

评论

0赞 sleighty 5/24/2021
子句不运行的唯一情况是当您跳出循环时,因此此示例不调用此类构造。也就是说,块内的任何代码都可能不需要语句(对于此示例)。else:else:else:
-1赞 Rahul Negi 5/22/2021 #12

假设您必须在单个链表中搜索元素 x

    def search(self, x):
        position = 1
        p =self.start
        while p is not None:
            if p.info == x:
                print(x, " is at position ", position)
                return True
            position += 1
            p = p.link
        else:
            print(x, "not found in list") 
            return False

因此,如果条件失败,否则将执行,希望它有所帮助!

评论

0赞 sleighty 5/24/2021
省略此代码段中的语句不会更改代码的行为。else:while
0赞 Rahul Negi 5/25/2021
@BrunoEly此代码是单个链表程序的片段,因此您需要一个完整的代码才能准确运行它。
3赞 sleighty 5/27/2021
你错过了我的观点。我想说的是,在块之后没有中断句的子句是没有意义的——它不会改变代码的行为。else:while
0赞 Rahul Negi 1/21/2023
是的,我明白了,IDK我是如何误解那次的(我的坏)。即使使用 break 语句,else 也不会执行。
2赞 Robert Siemer 1/15/2023 #13
thing = 'hay'
while thing:
  if thing == 'needle':
    print('I found it!!')  # wrap up for break
    break
  thing = haystack.next()
else:
  print('I did not find it.')  # wrap up for no-break

可能不幸命名的 -子句是你从循环耗尽中总结的地方,没有中断。else

  • 如果在这种情况下无事可做,则不需要 -子句else
  • 您在调用后中断或→整个代码,或者是您的不中断位置returnraisetry
  • 相反,您可以设置默认值(例如elsewhilefound = False)
    • 但它会引发与处理默认值相关的错误
    • -子句可以使您免于这些错误else

如果使用具有非平凡总结的多个中断,则应在中断之前使用简单的赋值,对无中断使用-子句赋值,并使用 -- 或 - 以避免重复非重复的中断处理代码。elseifelifelsematchcase

注意:以上所有内容也适用于for thing in haystack: