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

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


当前回答

由于技术部分已经回答了很多,我的评论只是与产生这个循环关键字的混淆有关。

由于Python是一种非常雄辩的编程语言,关键字的误用更加臭名昭著。else关键字完美地描述了决策树的部分流程,“如果你不能做这个,(else)做那个”。这在我们自己的语言中是隐含的。

相反,与while和for语句一起使用这个关键字会造成混淆。原因是,我们作为程序员的职业生涯告诉我们else语句存在于决策树中;它的逻辑作用域是一个有条件地返回要遵循的路径的包装器。同时,循环语句有一个象征性的明确目标来达到某些东西。目标是在流程的连续迭代之后实现的。

If / else表示要遵循的路径。循环遵循一条路径,直到“目标”完成。

问题是else这个词清楚地定义了条件中的最后一个选项。这个词的语义是Python和人类语言共享的。但是在人类语言中,这个词从来没有用来表示某人或某物在某事完成后将采取的行动。如果在完成它的过程中出现了问题(更像是break语句),就会使用它。

最后,关键字将保留在Python中。很明显这是一个错误,当每个程序员都试图像记忆工具一样想出一个故事来理解它的用法时,就更清楚了。如果他们选择了关键词,我会很喜欢的。我相信这个关键字非常适合迭代流程,即循环后的收益。

这就像有些孩子组装玩具的每一步都会遇到的情况:然后呢,爸爸?

其他回答

即使对经验丰富的Python程序员来说,这也是一个奇怪的结构。当与for-loops结合使用时,它的基本意思是“在可迭代对象中找到某个项,否则如果没有找到则do…”。如:

found_obj = None
for obj in objects:
    if obj.key == search_key:
        found_obj = obj
        break
else:
    print('No object found.')

但是无论何时你看到这个结构,一个更好的选择是将搜索封装在一个函数中:

def find_obj(search_key):
    for obj in objects:
        if obj.key == search_key:
            return obj

或者使用列表推导式:

matching_objs = [o for o in objects if o.key == search_key]
if matching_objs:
    print('Found {}'.format(matching_objs[0]))
else:
    print('No object found.')

它在语义上并不等同于其他两个版本,但在非性能关键代码中工作得足够好,在这些代码中,是否迭代整个列表并不重要。其他人可能不同意,但我个人会避免在生产代码中使用for-else或while-else块。

另参见[Python-ideas] for…其他线程

因为他们不想给这门语言引入一个新的关键字。每一个都窃取一个标识符并导致向后兼容问题,所以通常是最后的手段。

我想知道Python程序员是如何在头脑中(或者大声地,如果你喜欢)阅读这个结构的。

我只是在脑子里想:

“否则就没有中断……”

就是这样!

这是因为else子句只在for循环中没有遇到break语句时才执行。

参考:

请看这里:https://book.pythontips.com/en/latest/for_-_else.html#else-clause(强调添加,“not”改为“not”):

For循环还有一个我们大多数人都不熟悉的else子句。else子句在循环正常完成后执行。这意味着循环没有遇到break语句。


话虽如此,我还是不建议使用该语言的这个不同寻常的特性。不要在for循环之后使用else子句。这让大多数人感到困惑,并减慢了他们阅读和理解代码的能力。

The easiest way I found to 'get' what the for/else did, and more importantly, when to use it, was to concentrate on where the break statement jumps to. The For/else construct is a single block. The break jumps out of the block, and so jumps 'over' the else clause. If the contents of the else clause simply followed the for clause, it would never be jumped over, and so the equivalent logic would have to be provided by putting it in an if. This has been said before, but not quite in these words, so it may help somebody else. Try running the following code fragment. I'm wholeheartedly in favour of the 'no break' comment for clarity.

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        break
else: #no break  +10 for whoever thought of this decoration
    print('for completed OK')

print('statement after for loop')

编辑-我注意到这个问题仍然在运行

第二个更好的想法……

“没有休息”的评论是负面的。要理解一个正的断言要容易得多,那就是for可迭代对象已经用完了。

for a in range(3):
    print(a)
    if a==4: # change value to force break or not
        print('ending for loop with a break')
        break
else: # for iterable exhausted  
    print('ending for loop as iterable exhausted')

print('for loop ended one way or another')

这也强化了这种解释

if iterable_supplies_a_value:
    run_the_for_with_that_value
else:
    do_something_else

我是这样读的:

如果还在运行循环的条件下,做点别的,否则做点别的。