Ken*_*art 417 python for-loop if-statement for-else
我理解这个结构是如何工作的:
for i in range(10):
print(i)
if i == 9:
print("Too big - I'm giving up!")
break;
else:
print("Completed successfully")
Run Code Online (Sandbox Code Playgroud)
但我不明白为什么else在这里用作关键字,因为它表明有问题的代码仅在for块未完成时运行,这与它的作用相反!无论我如何看待它,我的大脑都无法从for语句无缝地进展到else块.对我来说,continue或者continuewith更有意义(我正在努力训练自己阅读它).
我想知道Python编码器如何在他们的脑海中读取这个结构(或者如果你愿意的话,大声朗读).也许我错过了一些会让这些代码块更容易破译的东西?
Lan*_*ten 501
一个常见的构造是运行一个循环直到找到某个东西,然后突破循环.问题是,如果我突破循环或循环结束,我需要确定发生了哪种情况.一种方法是创建一个标志或存储变量,让我进行第二次测试,看看如何退出循环.
例如,假设我需要搜索列表并处理每个项目,直到找到标记项目然后停止处理.如果缺少标志项,则需要引发异常.
使用Python for... else构造你有
for i in mylist:
if i == theflag:
break
process(i)
else:
raise ValueError("List argument missing terminal flag.")
Run Code Online (Sandbox Code Playgroud)
将此与不使用此语法糖的方法进行比较:
flagfound = False
for i in mylist:
if i == theflag:
flagfound = True
break
process(i)
if not flagfound:
raise ValueError("List argument missing terminal flag.")
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,raise它与for循环紧密绑定.在第二种情况下,绑定不是那么强,在维护期间可能会引入错误.
Bjö*_*ist 250
对于经验丰富的Python编码人员来说,这是一个奇怪的构造.当与for循环一起使用时,它基本上意味着"在迭代中找到一些项目,否则如果没有找到那么......".如:
found_obj = None
for obj in objects:
if obj.key == search_key:
found_obj = obj
break
else:
print('No object found.')
Run Code Online (Sandbox Code Playgroud)
但是无论何时你看到这个结构,一个更好的选择是将搜索封装在一个函数中:
def find_obj(search_key):
for obj in objects:
if obj.key == search_key:
return obj
Run Code Online (Sandbox Code Playgroud)
或者使用列表理解:
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.')
Run Code Online (Sandbox Code Playgroud)
它在语义上不等同于其他两个版本,但在非性能关键代码中运行良好,无论您是否迭代整个列表都无关紧要.其他人可能不同意,但我个人会避免在生产代码中使用for-else或while-else块.
另见[Python-ideas] for ... else线程的摘要
Air*_*Air 156
Raymond Hettinger的精彩演讲题为" 将代码转换为美丽的,惯用的Python",其中简要介绍了for ... else构造的历史.相关部分是"区分循环中的多个出口点",从15:50开始并持续约三分钟.以下是要点:
for ... else构造由Donald Knuth设计,作为某些GOTO用例的替代;else关键字是有道理的,因为"这是Knuth所使用的,而且人们知道,当时所有[ for陈述]都嵌入了一个if和GOTO下面,他们期待着else;"所以,如果问题是"为什么他们不改变这个关键字?" 那么Cat Plus Plus可能给出了最准确的答案 - 在这一点上,它对现有代码的破坏性太大而不实用.但是,如果你真正问的问题是为什么else首先重复使用,那么,显然当时这似乎是一个好主意.
就个人而言,我喜欢# no break在线评论的妥协,只要else错误,一眼就看出,归属于循环内部.它相当清晰简洁.这个选项在Bjorn在他的答案结尾处链接的摘要中简要提及:
为了完整起见,我应该提一下,如果语法略有变化,那么想要这种语法的程序员现在可以拥有它:
Run Code Online (Sandbox Code Playgroud)for item in sequence: process(item) else: # no break suite
*来自视频部分的奖金引用:"就像我们打电话给lambda makefunction一样,没有人会问,'lambda做什么?'"
Cat*_*lus 33
因为他们不想在语言中引入新的关键字.每个人窃取一个标识符并导致向后兼容性问题,因此它通常是最后的手段.
Ad *_*tum 26
为了简单起见,你可以这样想;
break在for循环中遇到命令,else则不会调用该部分.break命令,则将调用for该else部件.换句话说,如果循环迭代没有被"破坏" break,else则将调用该部分.
这很简单.
Nei*_*_UK 16
我发现'获得'for/else所做的最简单的方法,更重要的是,什么时候使用它,是专注于break语句跳转到的地方.For/else构造是一个单独的块.休息跳出块,因此跳过'else'条款.如果else子句的内容只是跟在for子句之后,它就永远不会被跳过,因此必须通过将它放在if中来提供等效逻辑.之前已经说过了,但不完全是这些,所以它可能对其他人有所帮助.尝试运行以下代码片段.为了清晰起见,我全心全意地赞成"不休息"的评论.
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')
Run Code Online (Sandbox Code Playgroud)
小智 15
我认为文档对其他方面有很好的解释 ,继续
[...]当循环通过列表的耗尽(with for)或条件变为false(with while)时终止,但是当循环被break语句终止时,它被执行."
Gab*_*les 10
我想知道 Python 程序员如何在头脑中(或者如果你愿意的话,可以大声地)读出这个结构。
我只是在心里想:
“不然就没有
break遇到过……”
就是这样!
这是因为else仅当循环break中未遇到语句时才执行该子句for。
参考:
请参阅此处:https: //book.pythontips.com/en/latest/for_-_else.html#else-clause(添加了重点,并将“not”更改为“NOT”):
for循环还有一个else我们大多数人都不熟悉的子句。该else子句在循环正常完成后执行。这意味着循环没有遇到break语句。
话虽这么说,我建议不要使用该语言的这种不寻常的功能。不要else在 for 循环之后使用该子句。这会让大多数人感到困惑,并且只会降低他们阅读和理解代码的能力。
小智 9
由于技术部分已得到很好的回答,我的评论只与产生这个回收关键字的混乱有关.
作为一种非常雄辩的编程语言,滥用关键字更加臭名昭着.该else关键字恰如其分地描述决策树的流程的一部分,"如果你不能做到这一点,(否则)做到这一点." 它隐含在我们自己的语言中.
相反,将此关键字与while和for语句一起使用会产生混淆.原因是,我们作为程序员的职业生涯告诉我们,else声明存在于决策树中; 它的逻辑范围,一个有条件地返回一个路径的包装器.同时,循环语句有一个具象的明确目标来达到某种目的.在连续迭代过程之后,目标得以实现.
if / else 指出要遵循的路径.循环遵循路径直到"目标"完成.
问题是这个else词清楚地定义了条件中的最后一个选项.Python和人类语言共享这个词的语义.但人类语言中的其他词语从未用于表示某事物完成后某人或某物所采取的行动.如果在完成它的过程中问题上升(更像是一个中断声明),它将被使用.
最后,关键字将保留在Python中.很明显这是错误的,当每个程序员试图想出一个故事来理解它的用法时会更清楚,就像一些助记设备一样.我喜欢他们是否选择了关键字then.我相信这个关键字非常适合迭代流程,循环后的收益.
它类似于一些孩子在组装玩具后的每一步都有的情况:那么爸爸呢?
很好的答案是:
我的笔记来自于 Donald Knuth 曾经说过的(抱歉找不到参考)有一个结构,其中 while-else 与 if-else 无法区分,即(在 Python 中):
x = 2
while x > 3:
print("foo")
break
else:
print("boo")
Run Code Online (Sandbox Code Playgroud)
具有与以下相同的流量(不包括低级别差异):
x = 2
if x > 3:
print("foo")
else:
print("boo")
Run Code Online (Sandbox Code Playgroud)
关键是 if-else 可以被认为是 while-else 的语法糖,它break在其if块的末尾隐含。相反的含义,while循环扩展到if,更常见(它只是重复/循环条件检查),因为if经常在while. 然而,事实并非如此,因为这意味着每次条件为假时else都会执行 while-else 中的块。
为了便于您的理解,可以这样想:
如果没有
break,return等,循环仅在条件不再为真时结束,在这种情况下else块也将执行一次。在 Python 的情况下,for您必须考虑 C 风格的for循环(带条件)或将它们转换为while.
另一个注意事项:
内部循环过早
break,return等使得条件不可能变为假,因为当条件为真时执行跳出循环,并且永远不会再回来检查它。
我同意,它更像是“省略(不提出条件)”。
我知道这是一个老话题,但是我现在正在研究相同的问题,而且我不确定有人以我理解的方式抓住了这个问题的答案。
对我来说,有三种“读取” elsein For... else或While... else语句的方法,所有这些方法都是等效的:
else == if the loop completes normally (without a break or error)else == if the loop does not encounter a breakelse == else not (condition raising break) (大概有这种情况,否则您将不会循环)因此,从本质上讲,循环中的“ else”实际上是一个“ elif ...”,其中“ ...”是(1)不间断,相当于(2)NOT [引起中断的条件]。
我认为关键是else没有'break'就没有意义,因此a for...else包括:
for:
do stuff
conditional break # implied by else
else not break:
do more stuff
Run Code Online (Sandbox Code Playgroud)
因此,for...else循环的基本元素如下,您将以普通英语阅读它们:
for:
do stuff
condition:
break
else: # read as "else not break" or "else not condition"
do more stuff
Run Code Online (Sandbox Code Playgroud)
正如其他张贴者所说的那样,当您能够找到要查找的循环时,通常会出现中断,因此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")
Run Code Online (Sandbox Code Playgroud)
结果
x: 0
x: 1
x: 2
ASSERTION ERROR: x is 2
----------
# loop not completed (hit break), so else didn't run
Run Code Online (Sandbox Code Playgroud)
例
一个简单的例子,打破休息。
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")
Run Code Online (Sandbox Code Playgroud)
结果
y: 0
y: 1
y: 2
BREAK: y is 2
----------
# loop not completed (hit break), so else didn't run
Run Code Online (Sandbox Code Playgroud)
例
一个简单的示例,其中没有中断,没有引发中断的条件,也没有遇到错误。
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")
Run Code Online (Sandbox Code Playgroud)
结果
z: 0
z: 1
z: 2
z_loop complete without break or error
----------
Run Code Online (Sandbox Code Playgroud)
该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.
Run Code Online (Sandbox Code Playgroud)
同样,可以认为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
Run Code Online (Sandbox Code Playgroud)
区别是python隐含的except break,您无法将其写出,因此它变为:
for x in iterable:
do_something(x)
else:
print('no break encountered') # No break statement was encountered
Run Code Online (Sandbox Code Playgroud)
是的,我知道这种比较可能很困难并且很累,但是确实可以澄清这种混淆。
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!
Run Code Online (Sandbox Code Playgroud)
循环语句可以包含else子句;当循环通过用尽列表而终止时(带有for)或条件变为假(具有while时),则执行此命令,但当循环由break语句终止时,则不执行该命令。以下循环示例搜索质数:
Run Code Online (Sandbox Code Playgroud)>>> 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语句具有更多的共同点:try语句的else子句在没有异常发生时运行,而循环的else子句在没有中断时发生运行。有关try语句和异常的更多信息,请参见处理异常。
也从C借用的continue语句继续循环的下一个迭代:
Run Code Online (Sandbox Code Playgroud)>>> 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
小智 5
这是一种我上面没有见过其他人提到的思考方式:
首先,请记住,for循环基本上只是while循环周围的语法糖。例如循环
for item in sequence:
do_something(item)
Run Code Online (Sandbox Code Playgroud)
可以(近似)重写为
item = None
while sequence.hasnext():
item = sequence.next()
do_something(item)
Run Code Online (Sandbox Code Playgroud)
其次,请记住,while循环基本上只是重复的if块!您始终可以将while循环读为“如果满足此条件,则执行主体,然后返回并再次检查”。
因此,while / else完全有道理:它与if / else完全相同,具有附加的循环功能,直到条件变为false为止,而不仅仅是检查条件一次。
然后for / else也很有意义:由于所有for循环只是while循环之上的语法糖,您只需要弄清楚底层while循环的隐式条件是什么,然后else对应于何时条件变为False。