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

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子句,了解语法含义的具体问题。


当前回答

这里是搜索之外的另一个惯用用例。假设您希望等待一个条件为真,例如,远程服务器上的一个端口打开,并伴有一些超时。然后你可以利用一点时间…其他结构如下:

import socket
import time

sock = socket.socket()
timeout = time.time() + 15
while time.time() < timeout:
    if sock.connect_ex(('127.0.0.1', 80)) is 0:
        print('Port is open now!')
        break
    print('Still waiting...')
else:
    raise TimeoutError()

其他回答

我同意,它更像是一个'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
----------

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

一个循环的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

我只是想让自己重新理解一下。我发现下面的方法很有用!

•将else看作是与循环中的if配对(而不是与for配对)-如果条件满足,则打破循环,否则执行此操作-除非它是与多个if配对的else ! •如果所有的“如果”都不满足,那么就做“其他”。 •多个如果实际上也可以被认为是if-elifs!

Raymond Hettinger做了一个非常棒的演讲,题为“将代码转换成美丽的、地道的Python”,在演讲中他简要地介绍了for Python的历史。其他结构。相关部分是“在循环中区分多个出口点”,从15:50开始,持续约3分钟。以下是要点:

for…else构造是由Donald Knuth设计的,作为某些GOTO用例的替代; 重用else关键字是有意义的,因为“它是Knuth使用的,人们知道,在那个时候,所有的(for语句)都在下面嵌入了一个if和GOTO,他们期望else;” 事后看来,它应该被称为“nobreak”(或者可能是“nobreak”),这样就不会让人困惑了

所以,如果问题是“为什么他们不改变这个关键字?”,那么Cat Plus Plus可能会给出最准确的答案——在这一点上,它对现有代码的破坏性太大了,不太实用。但如果你真正想问的问题是为什么其他东西一开始就被重用,嗯,显然这在当时看起来是个好主意。

就我个人而言,我喜欢折衷的注释# no break in-line,因为else可能会被误认为属于循环内部。它相当清晰简洁。Bjorn在他的回答结尾链接的摘要中简要提到了这个选项:

为了完整起见,我应该提一下 语法,想要这个语法的程序员现在就可以拥有它: 项目顺序如下: 过程(项目) Else: #不休息 套件


*视频中那部分的额外引用:“就像我们调用lambda makefunction一样,没有人会问,‘lambda是做什么的?’”