许多Python程序员可能不知道while
循环和for
循环的语法包含一个可选的else:
子句:
for val in iterable:
do_something(val)
else:
clean_up()
else
子句的主体是某些清理操作的好地方,并且在循环的正常终止时执行:即,使用return
或{{退出循环1}}跳过break
子句; else
执行后退出。我之所以知道这只是因为我只是looked it up(又一次),因为当执行continue
子句时我永远无法记住。
始终?在"失败"循环,顾名思义?定期终止?即使循环退出else
?如果不抬头,我永远无法完全确定。
我责怪我对关键字选择的持续存在的不确定性:我发现return
对于这种语义非常不符合要求。我的问题不是"为什么这个关键字用于此目的" (虽然只是在阅读了答案和评论之后,我可能会投票关闭,但是如何考虑else
关键字以使其语义有意义,因此我能记住它吗? /强>
我确信对此有相当多的讨论,我可以想象选择是为了与else
语句的try
条款(其中的一致性)保持一致我还必须查找),目的是不添加到Python的保留字列表中。也许选择else:
的原因将澄清其功能并使其更令人难忘,但我将名称与功能联系起来,而不是在历史解释本身之后。
this question的答案,其中我的问题作为副本暂时关闭,包含了许多有趣的背景故事。我的问题有一个不同的焦点(如何将else
的特定语义与关键字选择联系起来),但我觉得应该在某个地方找到这个问题的链接。
答案 0 :(得分:211)
(这是受@Mark Tolonen的回答启发的。)
if
语句如果条件的计算结果为false,则运行其else
子句。
同样,while
循环如果条件的计算结果为false,则运行else子句。
此规则与您描述的行为相符:
break
语句时,退出循环而不评估条件,因此条件不能计算为false,并且您永远不会运行else子句。continue
语句时,您再次评估条件,并完成您在循环迭代开始时的正常操作。
因此,如果条件为真,则保持循环,但如果为假,则运行else子句。return
)不会评估条件,因此不会运行else子句。 for
个循环的行为方式相同。如果迭代器有更多元素,只需将条件视为true,否则将其视为false。
答案 1 :(得分:36)
最好以这种方式来考虑:如果在前面的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")
continue
并未劫持for
的控制权,因此在else
用尽后,控件将继续for
。
答案 2 :(得分:30)
if
何时执行else
?当它的条件是假的。 while
/ else
完全相同。因此,您可以将while
/ else
视为一个if
,它一直运行其真实条件,直到它评估为false。 break
不会改变它。它只是包含循环的跳转而没有评估。仅当评估 else
/ if
条件为false时才会执行while
。
for
是类似的,除了它的错误条件是耗尽它的迭代器。
continue
和break
不执行else
。这不是他们的功能。 break
退出包含循环。 continue
返回到包含循环的顶部,其中评估循环条件。这是将if
/ while
评估为false(或for
没有更多项目)执行else
而无其他方式的行为。
答案 3 :(得分:24)
这实际上意味着:
for/while ...:
if ...:
break
if there was a break:
pass
else:
...
这是编写这种常见模式的更好方式:
found = False
for/while ...:
if ...:
found = True
break
if not found:
...
如果存在else
return
,则return
子句将不会执行,因为finally
将保留该函数。你可能想到的唯一例外是continue
,其目的是确保它始终被执行。
break
与此事无关。它导致循环的当前迭代结束,这可能发生在整个循环结束,显然在这种情况下循环没有以try/else
结束。
try:
...
except:
...
if there was an exception:
pass
else:
...
类似:
<my-directive apipoint="customerApi" modeldisplay="customer.selected"
ng-model="customer.selected" searchresults="customeruserprofile" change="customerChanged"></my-directive>
答案 4 :(得分:20)
如果你认为你的循环是一个类似于此的结构(有点伪代码):
loop:
if condition then
... //execute body
goto loop
else
...
它可能会更有意义。循环基本上只是一个if
语句,在条件为false
之前重复。这是重点。循环检查它的条件并看到它是false
,从而执行else
(就像普通的if/else
一样)然后完成循环。
请注意,else
仅在检查条件时执行。这意味着如果您在执行过程中退出循环体,例如return
或break
,因为不再检查条件,else
案例赢了“执行。
另一方面,continue
停止当前执行,然后再跳回来再次检查循环的情况,这就是在这种情况下可以达到else
的原因。
答案 5 :(得分:14)
我对循环的else
条款的关注时刻是我Raymond Hettinger观看演讲的时候,他讲了一个关于他应该怎么称呼nobreak
的故事。 }。看看下面的代码,您认为它会做什么?
for i in range(10):
if test(i):
break
# ... work with i
nobreak:
print('Loop completed')
你猜它会怎样?好吧,只有在循环中没有点击nobreak
语句时才会执行break
部分。
答案 6 :(得分:7)
通常我倾向于想到这样的循环结构:
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循环上的else
语句与else
链上的elif
语句完全相同,只有在它之前没有任何条件求值时才会执行真正。 (或使用return
或异常中断执行)如果我的循环不符合此规范,我通常会选择不使用for: else
,因为您发布此问题的确切原因:它不直观。
答案 7 :(得分:6)
其他人已经解释了while/for...else
的机制,Python 3 language reference具有权威定义(请参阅while和for),但这是我的个人助记符,FWIW 。我想我的关键是将其分解为两部分:一部分用于理解与循环条件相关的else
的含义,另一部分用于理解循环控制。
通过理解while...else
:
while
你有更多项目,做事,else
如果你用完了,就这样做
for...else
助记符基本相同:
for
每个项目,做一些事情,但如果你用完了else
,请执行此操作
在这两种情况下,else
部分只有在没有其他项目需要处理时才会到达,并且最后一项已经定期处理(即没有break
或{{1} })。 return
只会返回并查看是否还有其他项目。我对这些规则的助记符适用于continue
和while
:
for
或break
时,return
无法执行任何操作 当我说else
时,那个&#34;&#34;循环回到开始&#34;为你
- 用&#34;循环回到开始&#34;显然,这意味着循环的开始,我们检查迭代中是否还有其他项,因此就continue
而言,else
实际上根本没有任何作用。
答案 8 :(得分:6)
在Test-driven development(TDD)中,当使用Transformation Priority Premise范例时,将循环视为条件语句的泛化。
如果您只考虑简单的if/else
(无elif
)语句,则此方法与此语法完美结合:
if cond:
# 1
else:
# 2
概括为:
while cond: # <-- generalization
# 1
else:
# 2
很好。
在其他语言中,从单个案例到具有集合的案例的TDD步骤需要更多重构。
以下是8thlight blog的示例:
在8thlight博客的链接文章中,我们考虑使用Word Wrap kata:在字符串中添加换行符(下面的代码段中的s
变量),使它们适合给定的宽度(length
在下面的片段中的变量)。有一次,实现如下(Java):
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-&gt; while)转换,但作者发表评论:
虽然循环不能包含
else
子句,但我们需要通过在else
路径中减少if
路径来消除String result = ""; while (s.length() > length) { result += s.substring(0, length) + "\n"; s = s.substring(length); } result += s;
路径。同样,这是重构。
强制在一次失败测试的上下文中对代码进行更多更改:
result = ""
if len(s) > length:
result = s[0:length] + "\n"
s = s[length:]
else:
result += s
在TDD中,我们希望尽可能少地编写代码以使测试通过。感谢Python的语法,可以进行以下转换:
从:
result = ""
while len(s) > length:
result += s[0:length] + "\n"
s = s[length:]
else:
result += s
为:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" org.hibernate.HibernateException: Could not parse configuration: /hibernate.cfg.xml
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1491)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1425)
at org.hibernate.cfg.Configuration.configure(Configuration.java:1411)
at SimpleTest.main(SimpleTest.java:11)
Caused by: org.dom4j.DocumentException: Connection timed out: connect Nested exception: Connection timed out: connect
at org.dom4j.io.SAXReader.read(SAXReader.java:484)
at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:1481)
... 3 more
答案 9 :(得分:5)
我看到它的方式,else:
在迭代循环结束时触发。
如果您break
或return
或raise
没有超过循环结束,则会立即停止,因此else:
块赢了&# 39;跑。如果你continue
仍然迭代循环结束,那么继续只是跳到下一次迭代。它不会停止循环。
答案 10 :(得分:3)
将else
子句视为循环结构的一部分; break
完全打破了循环结构,因此跳过else
子句。
但实际上,我的心理映射只是它是模式C / C ++模式的“结构化”版本:
for (...) {
...
if (test) { goto done; }
...
}
...
done:
...
所以,当我遇到for...else
或自己编写时,而不是直接理解 ,我会在心理上将其转化为对模式的上述理解,然后找出python的哪些部分语法映射到模式的哪些部分。
(我把'结构化'放在恐慌引号中,因为差异不在于代码是结构化的还是非结构化的,而在于是否存在专用于特定结构的关键字和语法)
答案 11 :(得分:0)
我想到的方式,关键是要考虑continue
而不是else
的含义。
你提到的其他关键字突然出现循环(异常退出)而continue
没有,它只是跳过循环内部代码块的其余部分。它可以在循环终止之前的事实是偶然的:终止实际上是通过评估循环条件表达式以正常方式完成的。
然后你只需要记住在正常循环终止后执行else
子句。
答案 12 :(得分:0)
如果您尝试将else
与for
配对,可能会令人困惑。我不认为关键字else
是此语法的绝佳选择,但如果您将else
与break
配对,则可以看出它确实有意义。
让我用人类语言证明它。
for
一组嫌犯if
中的每个人都是罪犯break
调查。else
报告失败。
如果else
循环中没有break
,则for
几乎无用。
答案 13 :(得分:0)
# 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']
'''