为什么python在for和while循环之后使用“else”?
我明白这个构造是如何工作的:
for i in range(10): print(i) if i == 9: print("Too big - I'm giving up!") break; else: print("Completed successfully")
但是我不明白为什么在这里使用关键字,因为它表明只有在for
块没有完成的情况下才会运行代码,这与它所做的相反! 不pipe我怎么想,我的大脑都无法从for
语句无缝地for
到else
语句块。 对我而言, continue
或continuewith
会更有意义(我正在努力训练自己读取它)。
我想知道Python编程人员如何在头脑中读取这个构造(或者大声朗读,如果你喜欢的话)。 也许我错过了会使这样的代码块更容易辨认的东西?
对于经验丰富的Python编程人员来说,这是一个奇怪的构造。 当与for循环一起使用时,它基本上意味着“在迭代中find某个项目,否则如果没有find……”。 如:
found_obj = None for obj in objects: if obj.key == search_key: found_obj = obj break else: print 'No object found.'
但是无论何时你看到这个构造,更好的select是将search封装在一个函数中:
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', matching_objs[0] else: print 'No object found.'
它在语义上不等同于其他两个版本,但在非性能关键代码中工作良好,不pipe是否迭代整个列表都无关紧要。 其他人可能不同意,但我个人会避免在生产代码中使用for-else或while-else块。
另请参阅[Python-ideas] for … else线程的摘要
一个常见的构造是运行一个循环,直到find某个东西,然后跳出循环。 问题是如果我跳出循环或循环结束,我需要确定发生了什么情况。 一种方法是创build一个标志或存储variables,让我做第二次testing,看看如何退出循环。
例如,假设我需要search列表并处理每个项目,直到find标志项目,然后停止处理。 如果标志项丢失,则需要引发exception。
使用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循环绑定在一起。 在第二个绑定不那么强大,可能在维护过程中引入错误。
Raymond Hettinger发表了一篇名为“ 将代码转化为美丽的,习惯用法的Python ”的精彩演讲,其中他简要介绍了for ... else
构造的历史。 相关部分是“ 从15点50分开始区分循环中的多个出口点” ,并持续约3分钟。 这里是高点:
-
for ... else
构造是由Donald Knuthdevise的,作为某些GOTO
用例的替代; - 重用
else
关键字是有意义的,因为“这就是Knuth所使用的,当时人们都知道,所有的[语句]都embedded了一个if
和GOTO
,他们期望else
; - 事后看来,它应该被称为“不中断”(或者可能是“不中断”),然后它不会混淆。
所以,如果问题是“为什么他们不改变这个关键字?” 那么Cat Plus Plus可能会给出最准确的答案 – 在这一点上,对于现有的代码是非常具有破坏性的。 但是,如果你真正要问的问题是为什么else
原因被重用,那么显然这在当时似乎是一个好主意。
就我个人而言,我喜欢评论的妥协,无论在哪里, else
可能被误认为一目了然,因为它们属于循环内部。 这是相当清晰和简洁。 这个选项在摘要中简单地提到,比约恩在他的答案结尾处连接了:
为了完整起见,我应该提到,在语法上略有改变的时候,想要这个语法的程序员现在可以拥有它:
for item in sequence: process(item) else: # no break suite
这部分video的奖励引用:“就像我们称之为lambda makefunction一样,没有人会问'lambda做什么?'”
因为他们不想为这个语言引入一个新的关键字。 每个人都会窃取标识符并导致向后兼容性问题,所以通常是最后的手段。
我读过这样的东西:
如果仍然在运行循环的条件,做的东西, 否则做别的。
我发现最简单的方法是“获得”他/她做了什么,更重要的是,什么时候使用它,主要集中在break语句跳转到的地方。 For / else结构是一个单独的块。 rest跳出块,所以跳过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)结束时,或者当条件成为假(while)时执行,而不是在循环由break语句终止时执行。
来源: Python 2文档:控制stream程教程
我读起来就像“当iterable
器完全耗尽,并且在完成for
之后执行即将进入下一个语句,else子句将被执行。 因此,当迭代被break
,这将不会被执行。
由于技术部分已经得到了很好的回答,我的评论只是关于产生这个回收关键字的混淆 。
作为Python是一个非常有说服力的编程语言,滥用关键字更为臭名昭着。 else
关键字完美地描述了决策树的一部分stream程,“如果你不能这样做,(其他)做”。 这是暗示在我们自己的语言。
相反,在while
和for
语句中使用this关键字会造成混淆。 原因是,我们作为程序员的职业已经告诉我们, else
语句驻留在决策树中; 它的逻辑范围 ,一个有条件的返回path的包装。 同时,循环语句有一个比喻性的明确的目标来达成某些事情。 在一个过程的连续迭代之后,目标就会被满足。
if / else
表示要遵循的path 。 循环沿着path直到“目标”完成 。
这个问题是else
一个词,它清楚地定义了条件中的最后一个选项。 这个词的语义都是由Python和人类语言共享的。 但是人类语言中的其他词永远不会用来表示在某些事情完成之后某人或某事将要采取的行动。 如果在完成它的过程中出现问题,则会被使用(更像是断言 )。
最后,关键字将保持在Python中。 很明显,这是错误的,每个程序员试图想出一个故事来理解它的用法,比如一些助记符更清晰。 如果他们select了关键字,我会爱上它。 我相信这个关键字完全适合那个迭代stream,循环之后的收益 。
就像那个孩子在assembly一个玩具的每一步之后都有这样的情况: 那么爸爸呢?
我同意,这更像是一个'elif没有[条件(s)提高rest]“。
我知道这是一个古老的线索,但我现在正在研究同样的问题,而且我不确定是否有人以我理解的方式捕捉到这个问题的答案。
对于我来说,在For... else
或While... 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)NOT [condition(s)raise break]。
我认为关键在于else
方面没有“rest”是毫无意义的,所以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
正如其他海报所说的,当你能find你的循环所寻找的else:
时,通常会产生一个中断,所以else:
成为“如果目标项目没有定位,该怎么办”。
例
您也可以使用exception处理,中断和循环。
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
例
简单的例子,没有中断,没有条件提高rest,没有遇到错误。
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
是的,我知道这个比较可能是困难的,令人厌烦的,但它确实弄清了混淆。
你可以把它想象成其他的东西,或者其他东西,那些在循环中没有做的东西。
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!
从文档:打破和继续语句,否则条款上的循环
循环语句可能有一个else子句; 当循环通过用尽列表(用for)结束或者当条件变为false(用while)时执行,但是当循环由break语句终止时执行。 以下面的循环为例,它search素数:
>>> 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子句在没有发生exception时运行,并且在没有发生中断时运行循环的else子句。 有关try语句和exception的更多信息,请参阅处理exception。
从C中借用的continue语句继续下一个迭代循环:
>>> 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
为了简单起见,你可以这样想;
- 如果在
for
循环中遇到break
命令,则不会调用else
部分。 - 如果在
for
循环中没有遇到break
命令,则会调用else
部分。
这是如此简单。