提问人:alexis 提问时间:6/5/2016 最后编辑:alexis 更新时间:3/25/2023 访问量:14389
我怎样才能理解 Python 循环的“else”子句?
How can I make sense of the `else` clause of Python loops?
问:
许多 Python 程序员可能不知道 loops 和 loops 的语法包含一个可选子句:while
for
else:
for val in iterable:
do_something(val)
else:
clean_up()
子句的正文是某些类型的清理操作的好地方,在循环的正常终止时执行:即,退出循环或跳过子句;在执行它后退出。我之所以知道这一点,只是因为我刚刚(再次)查了一下,因为我永远不记得该条款是什么时候执行的。else
return
break
else
continue
else
总是?顾名思义,关于循环的“失败”?定期终止?即使循环以 ?如果不查一下,我永远无法完全确定。return
我把我持续的不确定性归咎于关键词的选择:我发现这种语义非常不可信。我的问题不是“为什么这个关键字用于此目的”(我可能会投票关闭,尽管只有在阅读了答案和评论之后),而是我如何考虑 else
关键字,使其语义有意义,因此我可以记住它?else
我敢肯定对此进行了相当多的讨论,我可以想象做出选择是为了与语句的子句保持一致(我也必须查找),并且目标是不添加到 Python 的保留字列表中。也许选择的原因会澄清它的功能并使其更令人难忘,但我是在将名称与功能联系起来,而不是在历史解释本身之后。try
else:
else
这个问题的答案,我的问题被短暂地关闭了,包含了很多有趣的背景故事。我的问题有不同的重点(如何将特定的语义与关键字选择联系起来),但我觉得应该在某个地方链接到这个问题。else
答:
何时执行?当其条件为 false 时。对于 /,它完全相同。因此,您可以将 / 视为一个继续运行其真实条件,直到它计算为 false 为止。A 不会改变这一点。它只是跳出包含循环,没有评估。仅当计算 / 条件为 false 时才执行。if
else
while
else
while
else
if
break
else
if
while
与此类似,只是其错误条件正在耗尽其迭代器。for
continue
并且不要执行.那不是他们的功能。退出包含循环。返回到包含循环的顶部,在那里评估循环条件。执行的是评估/为假(或没有更多项目)的行为,没有其他方式。break
else
break
continue
if
while
for
else
评论
else
continue
break
else
这就是它的本质含义:
for/while ...:
if ...:
break
if there was a break:
pass
else:
...
这是这种常见模式的更好编写方式:
found = False
for/while ...:
if ...:
found = True
break
if not found:
...
如果存在 because 离开函数,则不会执行该子句。您可能想到的唯一例外是 ,其目的是确保它始终被执行。else
return
return
finally
continue
与此事并没有什么特别的关系。它会导致循环的当前迭代结束,而这可能恰好结束了整个循环,显然在这种情况下,循环不是由 .break
try/else
是相似的:
try:
...
except:
...
if there was an exception:
pass
else:
...
如果你把你的循环想象成一个类似于这样的结构(有点伪代码):
loop:
if condition then
... //execute body
goto loop
else
...
这可能更有意义。循环本质上只是一个重复的语句,直到条件为 。这是重要的一点。循环检查其条件并查看它是 ,因此执行 (就像正常一样),然后循环完成。if
false
false
else
if/else
因此,请注意,当检查条件时,将执行唯一的 get。这意味着,如果在执行过程中使用 a 或 a 退出循环主体,因为没有再次检查条件,则不会执行该案例。else
return
break
else
另一方面,A 停止当前执行,然后跳回以再次检查循环的条件,这就是为什么在这种情况下可以达到 的原因。continue
else
评论
end
goto loop
if
if
最好这样想:如果前一个区块一切顺利,以至于耗尽,则该区块将始终被执行。else
for
在这种情况下,权利将意味着不,不,不。任何劫持控制权的语句都会导致该块被绕过。exception
break
return
for
else
在 中搜索项目时会发现一个常见的用例,在找到项目时取消搜索,或者通过以下块引发/打印标志:iterable
"not found"
else
for items in basket:
if isinstance(item, Egg):
break
else:
print("No eggs in basket")
A 不会劫持 的控制权,因此控制权将在 耗尽后继续进行。continue
for
else
for
评论
else
else
else
False
for
else
else
nobreak
if
while
for
break
else
continue
通常我倾向于认为循环结构是这样的:
for item in my_sequence:
if logic(item):
do_something(item)
break
很像可变数量的语句:if/elif
if logic(my_seq[0]):
do_something(my_seq[0])
elif logic(my_seq[1]):
do_something(my_seq[1])
elif logic(my_seq[2]):
do_something(my_seq[2])
....
elif logic(my_seq[-1]):
do_something(my_seq[-1])
在这种情况下,for 循环上的语句的工作方式与 s 链上的语句完全相同,它仅在计算结果为 True 之前的条件均未满足时执行。(或中断执行或异常)如果我的循环不符合这个规范,通常我会选择不使用,因为你发布这个问题的确切原因:它不直观。else
else
elif
return
for: else
评论
如果语句的条件计算结果为 false,则语句将运行其子句。
同样,如果循环的条件计算结果为 false,则循环将运行 else 子句。if
else
while
此规则与您描述的行为相匹配:
- 在正常执行中,while 循环会反复运行,直到条件的计算结果为 false,因此自然而然地退出循环会运行 else 子句。
- 当您执行语句时,您将退出循环而不计算条件,因此该条件的计算结果不能为 false,并且您永远不会运行 else 子句。
break
- 当您执行语句时,您将再次评估该条件,并完全按照您在循环迭代开始时通常执行的操作。
因此,如果条件为 true,则继续循环,但如果条件为 false,则运行 else 子句。
continue
- 退出循环的其他方法(如 )不计算条件,因此不运行 else 子句。
return
for
循环的行为方式相同。如果迭代器具有更多元素,则只需将条件视为 true,否则则视为 false。
评论
break
else
for
break
将子句视为循环构造的一部分; 完全脱离循环构造,从而跳过子句。else
break
else
但实际上,我的思维导图只是它是模式C / C++模式的“结构化”版本:
for (...) {
...
if (test) { goto done; }
...
}
...
done:
...
因此,当我自己遇到或编写它时,我不会直接理解它,而是在脑海中将其转化为上述对模式的理解,然后计算出 python 语法的哪些部分映射到模式的哪些部分。for...else
(我把“结构化”放在恐吓引号中,因为区别不在于代码是结构化的还是非结构化的,而只是是否有专门用于特定结构的关键字和语法)
评论
else
done:
else:
done:
else
goto
else
其他人已经解释了 的机制,Python 3 语言参考有权威的定义(参见 while 和 for),但这是我个人的助记符 FWIW。我想对我来说,关键是将其分解为两部分:一部分用于理解与循环条件相关的含义,另一部分用于理解循环控制。while/for...else
else
我发现最容易从理解开始:while...else
当你
有更多的物品时,做一些事情,否则
如果你用完了,就这样做
助记词基本相同:for...else
对于
每个项目,做一些事情,但如果你
用完了,就这样做
在这两种情况下,只有当没有更多项目需要处理,并且最后一个项目已以常规方式处理(即无或)时,才会到达该部分。A 只是回去看看是否还有更多项目。我对这些规则的助记符适用于以下两个方面:else
break
return
continue
while
for
当中断
或返回
时,没有其他事情
可做,当我说继续
时,
这对你来说就是“循环回到开始”
– “循环回到起点”的意思,显然,循环的开始,我们检查可迭代对象中是否还有更多项目,所以就 而言,实际上根本没有作用。else
continue
评论
else
break
else
else
else
else
我对循环从句的困惑时刻是当我在观看雷蒙德·赫廷格(Raymond Hettinger)的演讲时,他讲述了一个关于他认为应该如何称呼它的故事。看看下面的代码,你认为它会做什么?else
nobreak
for i in range(10):
if test(i):
break
# ... work with i
nobreak:
print('Loop completed')
你猜它有什么作用?好吧,只有当循环中没有命中语句时,才会执行说的部分。nobreak
break
在测试驱动开发 (TDD) 中,当使用转换优先级前提范式时,将循环视为条件语句的泛化。
如果您只考虑简单(无)语句,则此方法与此语法很好地结合在一起:if/else
elif
if cond:
# 1
else:
# 2
概括为:
while cond: # <-- generalization
# 1
else:
# 2
好。
在其他语言中,TDD 从单个案例到具有集合的案例需要更多的重构。
以下是 8thlight 博客中的一个示例:
在 8thlight 博客的链接文章中,考虑了 Word Wrap 套路:向字符串添加换行符(下面代码段中的变量)以使其适合给定的宽度(下面代码段中的变量)。在某一点上,实现如下所示(Java):s
length
String result = "";
if (s.length() > length) {
result = s.substring(0, length) + "\n" + s.substring(length);
} else {
result = s;
}
return result;
下一个测试,目前失败的是:
@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
}
因此,我们有有条件工作的代码:当满足特定条件时,添加换行符。我们希望改进代码以处理多个换行符。本文中提出的解决方案建议应用 (if->while) 转换,但作者评论说:
虽然循环不能有子句,所以我们需要通过在路径中做更少的操作来消除路径。同样,这是一个重构。
else
else
if
这迫使在一个失败的测试的上下文中对代码进行更多更改:
String result = "";
while (s.length() > length) {
result += s.substring(0, length) + "\n";
s = s.substring(length);
}
result += s;
在 TDD 中,我们希望编写尽可能少的代码以使测试通过。由于 Python 的语法,可以进行以下转换:
从:
result = ""
if len(s) > length:
result = s[0:length] + "\n"
s = s[length:]
else:
result += s
自:
result = ""
while len(s) > length:
result += s[0:length] + "\n"
s = s[length:]
else:
result += s
在我看来,当你迭代到循环的末尾时,就会触发它。else:
如果你或你没有迭代到循环的末尾,你就会立即停止,因此块不会运行。如果你仍然迭代到循环的末尾,因为继续只是跳到下一个迭代。它不会停止循环。break
return
raise
else:
continue
评论
goto
我的想法是,关键是要考虑 的含义而不是 .continue
else
你提到的其他关键字会跳出循环(异常退出),而没有,它只是跳过循环内代码块的其余部分。它可以在循环终止之前的事实是偶然的:终止实际上是通过计算循环条件表达式以正常方式完成的。continue
然后你只需要记住,该子句是在正常循环终止后执行的。else
如果与 配对,可能会造成混淆。我不认为关键字是这种语法的绝佳选择,但是如果您与 which contains 配对,您可以看到它实际上是有道理的。 如果没有前面的语句,则几乎没有用处,我相信这就是语法设计者选择关键字的原因。else
for
else
else
if
break
else
if
让我用人类语言来演示它。
for
每个人在一组嫌疑人中,任何人都是调查的罪犯。 报告失败。if
break
else
# tested in Python 3.6.4
def buy_fruit(fruits):
'''I translate the 'else' below into 'if no break' from for loop '''
for fruit in fruits:
if 'rotten' in fruit:
print(f'do not want to buy {fruit}')
break
else: #if no break
print(f'ready to buy {fruits}')
if __name__ == '__main__':
a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
buy_fruit(a_bag_of_apples)
buy_fruit(b_bag_of_apples)
'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''
带有子句的 while
语句else
while condition:
iteration
else:
conclusion
正好等同于
while True:
if not condition:
conclusion
break
iteration
带有子句的 for
语句else
for item in iterable:
iteration
else:
conclusion
正好等同于
iterator = iter(iterable)
while True:
try:
item = next(iterator)
except StopIteration:
conclusion
break
iteration
它有助于理解迭代语句中 or 语句的效果。break
continue
注意。— 对于不带子句的 and 语句,将结论语句替换为等效代码中的语句。while
for
else
pass
评论
for
StopIteration
next(iterator)
iteration
StopIteration
conclusion
上一个:如何在 Bash 中打破循环?
评论
else
关键字,以便它的语义有意义,因此我可以记住它?”- 具体向你解释我们如何帮助你个人记住作品不是一个有用的问题,Dharman是我撤回对这个问题的接近投票的唯一原因,因为没有它,这个问题是基于意见的else