我理解这种结构是如何运作的:

for i in range(10):
    print(i)

    if i == 9:
        print("Too big - I'm giving up!")
        break
else:
    print("Completed successfully")

但我不明白为什么在这里使用else作为关键字,因为它表明有问题的代码只在for块未完成时运行,这与它所做的相反!无论我怎么想,我的大脑都不能从for语句无缝地过渡到else语句块。对我来说,continue和continuouswith更有意义(我正试着训练自己这样读它)。

我想知道Python程序员是如何在头脑中(或者大声地,如果你喜欢)阅读这个结构的。也许我遗漏了一些可以使这些代码块更容易破译的东西?


这个问题是关于底层设计决策的,也就是说,为什么能够编写这些代码是有用的。另请参阅Python while语句中的Else子句,了解语法含义的具体问题。


当前回答

我同意,它更像是一个'elif not[条件(s)提高中断]'。

我知道这是一个老话题,但我现在正在研究同样的问题,我不确定是否有人能以我理解的方式抓住这个问题的答案。

对我来说,有三种方法来“阅读”For…else or While…所有等价的Else语句是:

Else ==如果循环正常完成(没有中断或错误) Else ==如果循环没有遇到断点 Else == Else not(条件引发中断)(假设存在这样的条件,否则就不会有循环)

因此,从本质上讲,循环中的“else”实际上是一个“elif…”,其中'…’表示(1)不中断,相当于(2)NOT[条件(s)引发中断]。

我认为关键在于,如果没有break, else是没有意义的,所以for…其他的包括:

for:
    do stuff
    conditional break # implied by else
else not break:
    do more stuff

a的基本元素。else循环如下所示,你可以用更简单的英语阅读它们:

for:
    do stuff
    condition:
        break
else: # read as "else not break" or "else not condition"
    do more stuff

正如其他帖子所说,当你能够找到你的循环正在寻找的东西时,通常会引发一个break,所以else:变成了“如果目标物品没有找到,该怎么办”。

例子

您还可以同时使用异常处理、中断和for循环。

for x in range(0,3):
    print("x: {}".format(x))
    if x == 2:
        try:
            raise AssertionError("ASSERTION ERROR: x is {}".format(x))
        except:
            print(AssertionError("ASSERTION ERROR: x is {}".format(x)))
            break
else:
    print("X loop complete without error")

结果

x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run

例子

一个简单的例子,断点被击中。

for y in range(0,3):
    print("y: {}".format(y))
    if y == 2: # will be executed
        print("BREAK: y is {}\n----------".format(y))
        break
else: # not executed because break is hit
    print("y_loop completed without break----------\n")

结果

y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run

例子

没有中断的简单示例,没有引发中断的条件,也没有遇到错误。

for z in range(0,3):
     print("z: {}".format(z))
     if z == 4: # will not be executed
         print("BREAK: z is {}\n".format(y))
         break
     if z == 4: # will not be executed
         raise AssertionError("ASSERTION ERROR: x is {}".format(x))
else:
     print("z_loop complete without break or error\n----------\n")

结果

z: 0
z: 1
z: 2
z_loop complete without break or error
----------

其他回答

一个循环的else分支只执行一次,不管这个循环是否进入它的循环体,除非循环体已经进入但没有结束。也就是说,在循环中会遇到break或return语句。

my_list = []
for i in my_list:
    print(i, end=',')
else:
    print('loop did not enter')

##################################    

for i in range(1,6,1):
    print(i, end=',')
else:
    print('loop completed successfully:', i)

##################################    

for i in range(1,6,1):
    if i == 3:
        print('loop did not finish:', i)
        break
    print(i, end=',')
else:
    print('else:', i)

输出:

loop did not enter
1,2,3,4,5,loop completed successfully: 5
1,2,loop did not finish: 3

while-else也是一样的。

import random
random.seed(8)

i = 100
while i < 90:
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('loop did not enter:', i)

##################################    

i = 25
while i < 90:
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('loop completed successfully:', i)

##################################    

i = 25
while i < 90:
    if i % 10 == 0:
        print('loop did not finish:', i)
        break
    print(i, end=',')
    i = random.randint(0,100)
else:
    print('else:', i)

输出:

loop did not enter: 100
25,29,47,48,16,24,loop completed successfully: 90
25,5,loop did not finish: 10

我认为结构是for(if) A else B,而for(if)-else是一个特殊的if-else。这可能有助于了解其他方面。

A和B最多执行一次,这与if-else结构相同。

For (if)可以被认为是一个特殊的if,它会执行一个循环来尝试满足if条件。一旦满足if条件,A和break;别的,B。

我把它读成这样:“当可迭代对象完全耗尽时,在完成for语句后,执行即将继续执行下一个语句,else子句将被执行。”因此,当迭代被break打断时,这将不会执行。

一个常见的构造是运行一个循环,直到找到一些东西,然后跳出循环。问题是,如果我跳出循环或循环结束,我需要确定发生了哪种情况。一种方法是创建一个标志或存储变量,让我进行第二次测试,以查看循环是如何退出的。

例如,假设我需要在列表中搜索并处理每个项,直到找到标志项,然后停止处理。如果缺少标志项,则需要引发异常。

使用Python进行…你的其他构念

for i in mylist:
    if i == theflag:
        break
    process(i)
else:
    raise ValueError("List argument missing terminal flag.")

将此方法与不使用此语法糖的方法进行比较:

flagfound = False
for i in mylist:
    if i == theflag:
        flagfound = True
        break
    process(i)

if not flagfound:
    raise ValueError("List argument missing terminal flag.")

在第一种情况下,raise与它所使用的for循环紧密绑定。第二种情况是,绑定不那么牢固,在维护过程中可能会出现错误。

很好的回答是:

这就解释了历史,而且 这就赋予了 引用以简化您的翻译/理解。

我在这里的注释来自Donald Knuth曾经说过(抱歉找不到参考),有一个结构,其中while-else与if-else无法区分,即(在Python中):

x = 2
while x > 3:
    print("foo")
    break
else:
    print("boo")

具有相同的流程(不包括低级别差异):

x = 2
if x > 3:
    print("foo")
else:
    print("boo")

关键是if-else可以被认为是while-else的语法糖,它在if块的末尾有隐含的break。相反的含义是,while循环是if的扩展,更常见(它只是重复/循环的条件检查),因为if经常在while之前教授。然而,这不是真的,因为这将意味着else块在while-else每次当condition为false时执行。

为了便于理解,可以这样想:

没有break, return等,循环只在condition不再为真时结束,在这种情况下else块也将执行一次。在Python for的情况下,你必须考虑c风格的for循环(带条件)或将它们转换为while。

另注:

循环中的过早中断、返回等使得condition不可能变为false,因为当condition为true时,执行跳出了循环,并且它永远不会再回来检查它。