我理解这种结构是如何运作的:
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和continuouswith更有意义(我正试着训练自己这样读它)。
我想知道Python程序员是如何在头脑中(或者大声地,如果你喜欢)阅读这个结构的。也许我遗漏了一些可以使这些代码块更容易破译的东西?
这个问题是关于底层设计决策的,也就是说,为什么能够编写这些代码是有用的。另请参阅Python while语句中的Else子句,了解语法含义的具体问题。
我想知道Python程序员是如何在头脑中(或者大声地,如果你喜欢)阅读这个结构的。
我只是在脑子里想:
“否则就没有中断……”
就是这样!
这是因为else子句只在for循环中没有遇到break语句时才执行。
参考:
请看这里:https://book.pythontips.com/en/latest/for_-_else.html#else-clause(强调添加,“not”改为“not”):
For循环还有一个我们大多数人都不熟悉的else子句。else子句在循环正常完成后执行。这意味着循环没有遇到break语句。
话虽如此,我还是不建议使用该语言的这个不同寻常的特性。不要在for循环之后使用else子句。这让大多数人感到困惑,并减慢了他们阅读和理解代码的能力。
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子句
Loop statements may have an else clause; it is executed when the loop terminates through exhaustion of the list (with for) or when the condition becomes false (with while), but not when the loop is terminated by a break statement. This is exemplified by the following loop, which searches for prime numbers:
>>> 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
(Yes, this is the correct code. Look closely: the else clause belongs to the for loop, not the if statement.)
When used with a loop, the else clause has more in common with the else clause of a try statement than it does that of if statements: a try statement’s else clause runs when no exception occurs, and a loop’s else clause runs when no break occurs. For more on the try statement and exceptions, see Handling Exceptions.
The continue statement, also borrowed from C, continues with the next iteration of the loop:
>>> 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
The easiest way I found to 'get' what the for/else did, and more importantly, when to use it, was to concentrate on where the break statement jumps to. The For/else construct is a single block. The break jumps out of the block, and so jumps 'over' the else clause. If the contents of the else clause simply followed the for clause, it would never be jumped over, and so the equivalent logic would have to be provided by putting it in an if. This has been said before, but not quite in these words, so it may help somebody else. Try running the following code fragment. I'm wholeheartedly in favour of the 'no break' comment for clarity.
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
即使对经验丰富的Python程序员来说,这也是一个奇怪的结构。当与for-loops结合使用时,它的基本意思是“在可迭代对象中找到某个项,否则如果没有找到则do…”。如:
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关键字可能会让人困惑,正如许多人指出的那样,像nobreak, notbreak这样的关键字更合适。
为了理解……其他的……从逻辑上讲,将它与try进行比较……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视为一种特殊的异常:
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暗示除了break,你不能把它写出来,所以它变成:
for x in iterable:
do_something(x)
else:
print('no break encountered') # No break statement was encountered
是的,我知道这种比较可能会很困难和令人厌倦,但它确实澄清了困惑。
下面是一种我从未见过其他人提到过的思考方法:
首先,请记住for循环基本上只是while循环的语法糖。例如,循环
for item in sequence:
do_something(item)
可以重写(大约)为
item = None
while sequence.hasnext():
item = sequence.next()
do_something(item)
其次,记住while循环基本上只是重复if块!你总是可以把while循环读成“如果这个条件为真,执行body,然后回来再次检查”。
因此while/else非常有意义:它与if/else结构完全相同,只是增加了循环直到条件变为false的功能,而不是只检查一次条件。
然后for/else也非常有意义:因为所有的for循环都只是while-循环之上的语法糖,你只需要弄清楚底层while-循环的隐式条件是什么,然后else对应于当条件变为False时。