为什么 python 在 for 和 while 循环后使用“else”?
- 2024-11-21 08:33:00
- admin 原创
- 37
问题描述:
我理解这个结构是如何工作的:
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
或continuewith
更有意义(我正在尝试训练自己这样阅读它)。
我想知道 Python 程序员如何在脑海中(或者大声朗读,如果你愿意的话)读懂这个结构。也许我遗漏了某些可以让此类代码块更易于解读的东西?
这个问题是关于底层设计决策的,即为什么能够编写此代码很有用。有关语法含义的具体问题,另请参阅Python while 语句中的 Else 子句。
解决方案 1:
一种常见的构造是运行循环直到找到某些东西,然后跳出循环。问题是,如果我跳出循环或循环结束,我需要确定发生了哪种情况。一种方法是创建一个标志或存储变量,让我进行第二次测试以查看循环是如何退出的。
例如,假设我需要搜索一个列表并处理每个项目,直到找到一个标志项目,然后停止处理。如果缺少标志项目,则需要引发异常。
使用 Python for
...else
构造你有
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 循环紧密绑定。在第二种情况下,绑定不那么牢固,维护期间可能会引入错误。
解决方案 2:
即使对于经验丰富的 Python 程序员来说,这也是一个奇怪的构造。当与 for 循环结合使用时,它基本上意味着“在可迭代对象中找到某个项,否则如果没有找到则执行...”。例如:
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...else 线程总结
解决方案 3:
Raymond Hettinger 有一篇精彩的演讲,题为《将代码转换为美观、惯用的 Python》,其中他简要介绍了该for ... else
构造的历史。相关部分是“区分循环中的多个出口点” ,从 15:50 开始,持续约三分钟。以下是精彩内容:
该
for ... else
结构由 Donald Knuth 设计,作为某些GOTO
用例的替代品;重复使用
else
关键字是有意义的,因为“这是 Knuth 所使用的,并且人们知道,当时,所有 [for
语句 ] 都在下面嵌入了一个if
andGOTO
,并且他们期待else
;”事后看来,它应该被称为“no break”(或可能是“nobreak”),这样就不会造成混淆。*
因此,如果问题是“他们为什么不改变这个关键字?”那么Cat Plus Plus 可能给出了最准确的答案——目前,它对现有代码的破坏性太大,不切实际。但如果你真正想问的问题是为什么else
一开始就被重复使用,那么,显然当时这似乎是个好主意。
就我个人而言,我喜欢在可能乍一看会误认为属于循环内部的地方使用# no break
内联注释的折衷方法else
。这种方法相当清晰简洁。Bjorn 在其答案末尾链接的摘要中简要提到了此选项:
为了完整起见,我应该提到,只要对语法进行轻微的改变,想要这种语法的程序员现在就可以拥有它:
for item in sequence: process(item) else: # no break suite
视频该部分的额外引言:“就像我们调用 lambda makefunction 时,没有人会问,‘lambda 做了什么?’”
解决方案 4:
为了简单起见,你可以这样想;
break
如果在循环中遇到该命令for
,else
则不会调用该部分。break
如果在循环中没有遇到该命令for
,else
则会调用该部分。
换句话说,如果 for 循环迭代没有被“中断” break
,那么该else
部分就会被调用。
解决方案 5:
因为他们不想在语言中引入新的关键字。每个关键字都会窃取标识符并导致向后兼容性问题,所以这通常是最后的手段。
解决方案 6:
我发现,要“了解” for/else 的作用,以及更重要的是何时使用它,最简单的方法是专注于 break 语句跳转到的位置。For/else 构造是一个单独的块。break 跳出该块,因此跳过了 else 子句。如果 else 子句的内容只是跟在 for 子句后面,则永远不会被跳过,因此必须通过将其放在 if 中来提供等效逻辑。这之前已经说过,但不是完全用这些话,所以它可能对其他人有帮助。尝试运行以下代码片段。为了清晰起见,我完全赞成使用“no break”注释。
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: # when 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
解决方案 7:
我认为文档对else有很好的解释 ,继续
[...] 它是在循环因耗尽列表而终止时(使用 for)或当条件变为假时(使用 while)执行的,但不是在循环被 break 语句终止时执行的。
来源:Python 2 文档:控制流教程
解决方案 8:
由于技术部分已经基本得到解答,我的评论只是与产生这个回收关键字的混淆有关。
Python 是一种非常流畅的编程语言,但关键字的误用却更为臭名昭著。该else
关键字完美地描述了决策树流程的一部分,“如果你不能这样做,(否则)就那样做”。这在我们自己的语言中是隐含的。
相反,将此关键字与while
andfor
语句一起使用会造成混淆。原因是,我们作为程序员的职业生涯告诉我们,语句else
位于决策树中;它的逻辑范围,一个有条件地返回要遵循的路径的包装器。同时,循环语句有一个比喻性的明确目标来达到某个目标。该目标在流程的连续迭代后得以实现。
if / else
指示要遵循的路径。循环遵循路径,直到“目标”完成。
问题是,else
这个单词明确定义了条件中的最后一个选项。该单词的语义在 Python 和人类语言中都是相同的。但是人类语言中的 else 单词从不用于表示某人或某事在某事完成后将采取的行动。如果在完成过程中出现问题(更像是break语句),则会使用它。
最后,关键字将保留在 Python 中。很明显,这是一个错误,当每个程序员都试图想出一个故事来理解它的用法(就像某种助记符一样)时,情况会更加清楚。如果他们选择关键字,我会很高兴then
。我相信这个关键字非常适合迭代流程,即循环后的回报。
这类似于一些孩子在按照每个步骤组装玩具后遇到的情形:然后爸爸呢?
解决方案 9:
好的答案是:
这解释了历史,
这提供了正确的引用以简化您的翻译/理解。
我在这里的注释来自 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 的语法糖,后者break
在块的末尾有 implicit if
。相反的含义是,while
循环是 的扩展if
,这更常见(它只是重复/循环的条件检查),因为if
通常在 之前教授while
。然而,事实并非如此,因为这意味着每次else
当条件为假时,while-else 中的块都会被执行。
为了便于你理解,可以这样想:
如果没有
break
、return
等,循环仅在条件不再为真时结束,在这种情况下else
块也将执行一次。对于 Python,for
您必须考虑 C 样式for
循环(带条件)或将其转换为while
。
另请注意:
循环内部过早的
break
、return
等等使得条件不可能变为假,因为当条件为真时执行会跳出循环,并且永远不会回来再次检查它。
解决方案 10:
我读到的内容是这样的:
如果仍然满足运行循环的条件,则执行操作,否则执行其他操作。
解决方案 11:
我想知道 Python 程序员如何在脑海中读出这个结构(或者如果你愿意的话,大声读出来)。
我只是在心里想:
“否则没有
break
遇到……”
就是这样!
这是因为else
仅当循环break
中未遇到语句时才会执行该子句for
。
参考:
请参阅此处: https: //book.pythontips.com/en/latest/for_-_else.html#else-clause(添加了强调,并将“not”更改为“NOT”):
for
循环还有一个else
我们大多数人都不熟悉的子句。该else
子句在循环正常完成后执行。这意味着循环没有遇到 break 语句。
话虽如此,我建议不要使用该语言的这个不寻常的功能。不要else
在 for 循环后使用该子句。它会让大多数人感到困惑,并且会降低他们阅读和理解代码的能力。
解决方案 12:
这里的关键词else
可能会令人困惑,正如许多人指出的那样,像 这样的关键词nobreak
更为notbreak
合适。
为了从for ... else ...
逻辑上理解,将其与 进行比较try...except...else
,而不是if...else...
,大多数python程序员都熟悉以下代码:
try:
do_something()
except:
print("Error happened.") # The try block threw an exception
else:
print("Everything is find.") # The try block does things just find.
类似地,把 想象break
成一种特殊的Exception
:
for x in iterable:
do_something(x)
except break:
pass # Implied by Python's loop semantics
else:
print('no break encountered') # No break statement was encountered
这个区别是python
隐含的except break
,你无法写出来,所以它变成:
for x in iterable:
do_something(x)
else:
print('no break encountered') # No break statement was encountered
是的,我知道这种比较可能很困难而且令人厌烦,但它确实澄清了混淆。
解决方案 13:
我读到的是“当iterable
完全耗尽,并且执行即将在 完成后继续执行下一个语句时for
,将执行 else 子句。”因此,当迭代被 中断时break
,这将不会被执行。
解决方案 14:
我同意,它更像是“elif not [条件引发中断]”。
我知道这是一个老话题,但我现在正在研究同样的问题,而且我不确定是否有人按照我理解的方式找到了这个问题的答案。
对我来说,有三种“读取” else
inFor... else
或While... else
语句的方法,它们都是等效的,分别是:
else
==
if the loop completes normally (without a break or error)
else
==
if the loop does not encounter a break
else
==
else not (condition raising break)
(假设存在这样的情况,否则你不会有循环)
因此,本质上,循环中的“else”实际上是“elif ...”,其中‘...’表示 (1) 无中断,相当于 (2) 非 [引发中断的条件]。
我认为关键是如果else
没有“中断”,那么就没有意义,因此for...else
包括:
for:
do stuff
conditional break # implied by else
else not break:
do more stuff
因此,循环的基本元素for...else
如下,您可以用更简单的英语阅读它们:
for:
do stuff
condition:
break
else: # read as "else not break" or "else not condition"
do more stuff
正如其他海报所说,当您能够找到循环所寻找的内容时,通常会引发中断,因此就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 {}
----------".format(y))
break
else: # not executed because break is hit
print("y_loop completed without break----------
")
结果
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 {}
".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
----------
")
结果
z: 0
z: 1
z: 2
z_loop complete without break or error
----------
解决方案 15:
当循环没有被打破时,语句块内的代码else
都会被执行。for
for x in xrange(1,5):
if x == 5:
print 'find 5'
break
else:
print 'can not find 5!'
#can not find 5!
来自文档:break 和 continue 语句,以及循环中的 else 子句
循环语句可以有一个 else 子句;当循环因耗尽列表而终止(使用 for)或条件变为 false(使用 while)时,它会被执行,但当循环被 break 语句终止时不会执行。以下循环就是一个例子,它搜索素数:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print(n, 'equals', x, '*', n//x) ... break ... else: ... # loop fell through without finding a factor ... print(n, 'is a prime number') ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3
(是的,这是正确的代码。仔细看:else 子句属于 for 循环,而不是 if 语句。)
与循环一起使用时,else 子句与 try 语句的 else 子句的共同点多于与 if 语句的 else 子句的共同点:try 语句的 else 子句在未发生异常时运行,而循环的 else 子句在未发生 break 时运行。有关 try 语句和异常的更多信息,请参阅处理异常。
continue 语句也是从 C 语言中借用的,它继续循环的下一次迭代:
>>> for num in range(2, 10): ... if num % 2 == 0: ... print("Found an even number", num) ... continue ... print("Found a number", num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 9
解决方案 16:
这是我上面没有看到其他人提及的一种思考方式:
首先,请记住 for 循环基本上只是 while 循环的语法糖。例如,循环
for item in sequence:
do_something(item)
可以(近似地)重写为
item = None
while sequence.hasnext():
item = sequence.next()
do_something(item)
其次,请记住,while 循环基本上只是重复的 if 块!您始终可以将 while 循环理解为“如果此条件为真,则执行主体,然后返回并再次检查”。
因此 while/else 非常有意义:它与 if/else 具有完全相同的结构,但增加了循环功能,直到条件变为假,而不仅仅是检查一次条件。
然后 for/else 也完全有意义:因为所有的 for 循环都只是 while 循环之上的语法糖,你只需要弄清楚底层 while 循环的隐式条件是什么,然后 else 就对应于该条件变为 False 的时候。
解决方案 17:
for i in range(3):
print(i)
if i == 2:
print("Too big - I'm giving up!")
break;
else:
print("Completed successfully")
这里的“else”非常简单,只是意味着
1、“如果for clause
完成”
for i in range(3):
print(i)
if i == 2:
print("Too big - I'm giving up!")
break;
if "for clause is completed":
print("Completed successfully")
编写像“for 子句已完成”这样的长语句很困难,因此他们引入了“else”。
else
就其本质而言,这是一个“如果”。
2,但是,for clause is not run at all
In [331]: for i in range(0):
...: print(i)
...:
...: if i == 9:
...: print("Too big - I'm giving up!")
...: break
...: else:
...: print("Completed successfully")
...:
Completed successfully
所以它的完整陈述是逻辑组合:
if "for clause is completed" or "not run at all":
do else stuff
或者这样说:
if "for clause is not partially run":
do else stuff
或者这样:
if "for clause not encounter a break":
do else stuff
解决方案 18:
除了搜索之外,这里还有另一个惯用的用例。假设您想要等待某个条件为真,例如远程服务器上的端口打开,以及一些超时。那么您可以使用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()
解决方案 19:
我只是想自己再理解一下。我发现以下内容很有帮助!
• 认为 是else
与循环内的 配对if
(而不是 与for
) - 如果条件满足,则中断循环,否则执行此操作 - 除非它else
与多个if
s 配对! • 如果根本
没有s 得到满足,则执行。
• 多个s 实际上也可以被认为是- s!if
`else` if
`if`elif
解决方案 20:
else 子句在循环正常完成后执行。这意味着,
仅当循环未由 break 语句终止时,才会执行 for/while 之后的 :==> else 块
for item in lista:
if(obj == item ):
print("if True then break will run and else not run")
break;
else:
print("in else => obj not fount ")
解决方案 21:
无论循环是否进入其主体,循环的 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
解决方案 22:
对于程序员来说,这可能看起来令人困惑,因为我们总是期望在if
面对时看到else
,但在现实生活中我们else
使用for
举个例子,我让我的儿子在书架上找一本字典并把它拿给我,如果他找不到,那么他就应该去给我买一本
这是algorithm
心中his
for book in bookshelf:
if book == 'dictionary':
#Lucky Me !! I find it lets bring it to dad
bring('dictionary')
break #and of course I break and stop searching
else: #too bad :( we do not have any dictionaries
buy('dictionary');
解决方案 23:
for i in range(10):
print(i)
if i == 9:
print("Too big - I'm giving up!")
break;
else:
print("Completed successfully")
break 关键字用于结束循环。如果 i = 9,则循环结束。当任何if条件不满足时,将else
执行剩下的部分。
解决方案 24:
您可以将其想象else
成其余的东西,或者其他未在循环中完成的东西。
解决方案 25:
我认为该结构类似于 for (if) A else B,而 for(if)-else大致是一种特殊的 if-else。它可能有助于理解else。
A和B最多执行一次,与if-else结构相同。
for(if) 可以看作是一种特殊的 if,它会进行循环以尝试满足 if 条件。一旦满足if条件,A 和break;否则,B。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件