我了解此构造的工作原理:
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 编码人员是如何在他们的脑海中阅读这个结构的(或者大声,如果你愿意的话)。也许我错过了一些可以让这些代码块更容易被破译的东西?
break
在 “我找到了” 循环中被大量使用,您可以将其翻译为 “如果未找到”,这与else
读什么
for ... else foo()
和将 foo()
放在 for 循环之后有什么区别?”答案是,仅在循环包含 break
时它们的行为不同(如下文详细描述)。
一个常见的结构是运行一个循环,直到找到一些东西,然后退出循环。问题是,如果我跳出循环或循环结束,我需要确定发生了哪种情况。一种方法是创建一个标志或存储变量,让我进行第二次测试以查看循环是如何退出的。
例如假设我需要搜索一个列表并处理每个项目,直到找到一个标志项目然后停止处理。如果缺少标志项,则需要引发异常。
使用您拥有的 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 循环紧密绑定。在第二种情况下,绑定没有那么强,并且在维护期间可能会引入错误。
即使对于经验丰富的 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] Summary of for...else threads
for
循环示例,并且想要使用生成器表达式/列表推导,那么您需要 next((o for o in objects if o.key == search_key), None)
或将其包装在 try
/ except
中并使用没有默认值而不是 if
/ else
。
for/else
构造。
else
与 for
配对,我不知道这是合法的。
break
语句如本例中那样显式运行。从上面的文档中:“else
子句还有另一个问题:如果循环中没有 break
,则 else
子句在功能上是多余的。”。例如for x in [1, 2, 3]:\n print x\n else:\n print 'this executes due to no break'
Raymond Hettinger 有一个出色的演示文稿,标题为 Transforming Code into Beautiful, Idiomatic Python,他在其中简要介绍了 for ... else
构造的历史。相关部分是“区分循环中的多个退出点”starting at 15:50,持续约三分钟。以下是要点:
for ... else 构造是由 Donald Knuth 设计的,用于替代某些 GOTO 用例;
重用 else 关键字是有道理的,因为“这是 Knuth 使用的,人们知道,当时所有 [for 语句] 都在下面嵌入了 if 和 GOTO,他们期待 else;”
事后看来,它应该被称为“no break”(或者可能是“nobreak”),这样就不会令人困惑了。*
所以,如果问题是,“他们为什么不改变这个关键字?”然后 Cat Plus Plus probably gave the most accurate answer - 在这一点上,它对现有代码的破坏性太大而无法实用。但是,如果您真正要问的问题是为什么首先要重用 else
,那么显然这在当时似乎是个好主意。
就个人而言,我喜欢在 else
可能被误认为属于循环内部的任何地方注释 # no break
的折衷方案。它相当清晰和简洁。这个选项在他的回答末尾的 the summary that Bjorn linked 中得到了简短的提及:
为了完整起见,我应该提一下,只要稍微改变一下语法,想要这种语法的程序员现在就可以拥有它: for item in sequence: process(item) else: # no break suite
* 视频那部分的额外引述:“就像我们调用 lambda makefunction 一样,没有人会问,'lambda 做什么?'”
__future__
导入除法以将 / 替换为标准除法并添加 // 地板除法运算符。
nobreak
关键字可能更明显,也许这确实是一种改进语法的方法。
为了简单起见,你可以这样想;
如果在 for 循环中遇到 break 命令,则不会调用 else 部分。
如果在for循环中没有遇到break命令,就会调用else部分。
换句话说,如果 for 循环迭代没有被 break
“破坏”,则 else
部分将被调用。
else
块。
for/else
读作 for/nobreak
。
因为他们不想在语言中引入新的关键字。每个人都会窃取一个标识符并导致向后兼容性问题,因此它通常是最后的手段。
我认为文档对 else 有很好的解释,继续
[...] 当循环因列表用尽而终止时(使用 for)或条件变为假(使用 while)时执行,但不会在循环被 break 语句终止时执行。”
来源:Python 2 docs: Tutorial on control flow
我发现“获取” for/else 所做的最简单的方法,更重要的是,何时使用它,是专注于 break 语句跳转到的位置。 For/else 构造是单个块。 break 跳出块,因此跳过了 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')
编辑 - 我注意到这个问题仍在运行
第二个更好的想法...
“不中断”评论是否定的。理解肯定断言要容易得多,那就是 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
for:
/else:
,但它没有' t 确实为关键字 else
提供了理由。鉴于此处给出的框架,then:
似乎更自然。 (在其他答案中给出了选择 else
的有个原因 - 它们只是没有在此处提供。)
我读到它是这样的:
如果仍然有条件运行循环,则做一些事情,否则做其他事情。
for:
/else:
的这种发音听起来好像 else:
将始终在循环之后运行,但事实并非如此。
由于技术部分已经得到了相当多的回答,我的评论只是与产生这个回收关键字的混淆有关。
由于 Python 是一种非常雄辩的编程语言,因此滥用关键字更加臭名昭著。 else
关键字完美地描述了决策树流程的一部分,“如果你不能这样做,(否则)就这样做”。它在我们自己的语言中暗示。
相反,将此关键字与 while
和 for
语句一起使用会造成混淆。原因是,我们作为程序员的职业告诉我们 else
语句位于决策树中;它的逻辑范围,一个有条件地返回要遵循的路径的包装器。同时,循环语句有一个象征性的明确目标来达到某些目标。在一个过程的不断迭代之后,目标才能实现。
if / else
指明要遵循的路径。循环沿着一条路径直到“目标”完成。
问题是 else
是一个明确定义条件中最后一个选项的词。单词的语义由 Python 和人类语言共享。但是人类语言中的 else 词从不用于表示某人或某物在完成某事后将采取的行动。如果在完成它的过程中出现问题(更像是 break 语句),将使用它。
最后,关键字将保留在 Python 中。很明显,这是错误的,当每个程序员都试图想出一个故事来理解它的用法时,就更清楚了,就像一些助记器一样。如果他们选择了关键字 then
,我会很高兴的。我相信这个关键字非常适合那个迭代流程,循环之后的payoff。
这类似于某些孩子在组装玩具的每一步之后所遇到的情况:然后爸爸呢?
很好的答案是:
这解释了历史,并且
这提供了正确的引用来简化您的翻译/理解。
我在这里的注释来自 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 的语法糖,它在 if
块的末尾有隐式 break
。相反的含义,即 while
循环是对 if
的扩展,更常见(它只是重复/循环条件检查),因为 if
通常在 while
之前教授。但是,这不是真的,因为这意味着当条件为假时,每次都会执行 while-else 中的 else
块。
为了便于理解,请这样想:
如果没有 break、return 等,循环仅在条件不再为真时结束,在这种情况下 else 块也将执行一次。在 Python for 的情况下,您必须考虑 C 风格的 for 循环(带条件)或将它们转换为 while。
另一个注意事项:
循环内的过早中断、返回等使得条件不可能变为假,因为在条件为真时执行跳出循环并且它永远不会再回来检查它。
我想知道 Python 编码人员是如何在他们的脑海中阅读这个结构的(或者大声,如果你愿意的话)。
我只是在脑海里想:
“否则没有遇到中断……”
而已!
这是因为只有在 for
循环中没有遇到 break
语句时才会执行 else
子句。
参考:
请参见此处:https://book.pythontips.com/en/latest/for_-_else.html#else-clause(添加了重点,并且“not”更改为“NOT”):
for 循环还有一个我们大多数人都不熟悉的 else 子句。 else 子句在循环正常完成后执行。这意味着循环没有遇到 break 语句。
话虽如此,我建议反对使用该语言的这种不寻常的功能。不要在 for 循环后使用 else
子句。这让大多数人感到困惑,只会减慢他们阅读和理解代码的能力。
我把它读成“当iterable
完全用尽,并且在完成for
后将执行下一条语句时,将执行else子句。”因此,当迭代被 break
中断时,这将不会被执行。
我同意,这更像是“elif not [condition(s) raise break]”。
我知道这是一个旧线程,但我现在正在研究同一个问题,我不确定是否有人以我理解的方式捕捉到这个问题的答案。
对我来说,有三种“阅读”For... else
或 While... else
语句中的 else
的方法,它们都是等效的,它们是:
else == 如果循环正常完成(没有中断或错误) else == 如果循环没有遇到中断 else == else not(条件引发中断)(大概有这样的条件,或者你不会有一个循环)
所以,本质上,循环中的“else”实际上是一个“elif ...”,其中“...”是(1)没有中断,相当于(2)NOT [condition(s) raise break]。
我认为关键是 else
没有“break”是毫无意义的,所以 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 {}\n----------".format(y))
break
else: # not executed because break is hit
print("y_loop completed without break----------\n")
结果
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 {}\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")
结果
z: 0
z: 1
z: 2
z_loop complete without break or error
----------
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
是的,我知道这种比较可能既困难又令人厌烦,但它确实澄清了困惑。
try: stuff(); except: error(); else: ok()
和 try: stuff(); ok(); except: error()
真的不一样吗?
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!
从docs: break and continue Statements, and else Clauses on Loops
循环语句可能有一个 else 子句;它在循环因列表用尽而终止时(使用 for)或条件变为假(使用 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: ... # 循环失败而没有找到因子 ... print(n, '是质数') ... 2 是质数 3 是质数 4 等于 2 * 2 5 是质数 6 等于 2 * 3 7 是质数 8 等于 2 * 4 9 等于 3 * 3 (是的,这是正确的代码。仔细观察:else 子句属于 for 循环,而不是 if 语句。)当与循环一起使用时,else 子句与 try 语句的 else 子句有更多的共同点。与 if 语句类似:try 语句的 else 子句在没有异常发生时运行,循环的 else 子句在没有中断发生时运行。有关 try 语句和异常的更多信息,请参阅处理异常。同样从 C 中借用的 continue 语句继续循环的下一次迭代: >>> for num in range(2, 10): ... if num % 2 == 0: ... print("Found an even number", num) ... continue ... print("Found a number", num) 找到一个偶数 2 找到一个数字 3 找到一个偶数 4 找到一个数字 5 找到一个偶数 6 找到一个数字 7找到一个偶数 8 找到一个数字 9
这是我在上面没有看到其他人提到的一种思考方式:
首先,请记住 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 的结构完全相同,增加了循环直到条件变为 false 的功能,而不是只检查一次条件。
然后 for/else 也很有意义:因为所有 for 循环都只是 while 循环之上的语法糖,你只需要弄清楚底层 while 循环的隐式条件是什么,然后 else 对应于什么时候条件变为 False。
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
本质上是一个 if。
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
这是除了搜索之外的另一个惯用用例。假设您想等待某个条件为真,例如在远程服务器上打开一个端口,以及一些超时。然后您可以像这样使用 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()
我只是想自己重新弄明白。我发现以下有帮助!
• 将 else
视为与循环内的 if
配对(而不是与 for
) - 如果满足条件则中断循环,否则执行此操作 -除了它是一个 else
与多个 if
配对!
• 如果根本不满足任何 if
,则执行 else
。
• 多个 if
实际上也可以认为是 if
-elif
s!
您可以将它想象为 else
与其他内容或其他内容一样,这些内容不是在循环中完成的。
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
将完成剩下的部分。
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 ")
我认为结构与 (if) A else B 相同,而 for(if)-else 大致是一个特殊的 if-else。理解其他可能会有所帮助。
A和B最多执行一次,与if-else结构相同。
for(if) 可以被认为是一个特殊的 if,它执行一个循环来尝试满足 if 条件。一旦满足if条件,A和break;否则,B.
Python: the good parts
书。process(i)
发生在mylist
中的每个项目都严格在theflag
之前,而不是theflag
本身?这是预期的吗?process
将在到达theflag
之前对列表中存在的每个i
执行,不会对theflag
之后的列表中的元素执行,也不会在theflag
上执行。