【Python】你还在看到for循环后写else后,大呼【卧槽,牛逼!】【卧槽,还能这样?】吗?
摘自书籍 Effective Python
Python 有种特殊语法是很多编程语言都不支持的,可以在for及while循环的内部语句快之后紧跟一个else块。
for i in range(3):
print("Loop {}".format(i))
else:
print("Else Block!")
# Loop 0
# Loop 1
# Loop 2
# Else Block!
这种else块会在整个循环正常结束后立刻执行。既然如此,为什么它叫做else,而不是and呢?在if/else语句中,else的意思是:如果不执行前面的if块,那就执行else块。在try/except语句中,except的定义也类似:如果前面的try块没有执行成功,那就执行except块。
同for/else一样的道理,try/except/else也是如此,该结构的else的含义是:如果前面的try块没有失败,就执行else块。try/finally同样非常直观,这里的finally的意思是,不论try有没有正常执行,最终都要执行finally块。
明白了else,except,finally的含义之后,刚接触Python的程序员或没有了解过for/else结构的程序员可能会把for/else结构中的else理解为:如果循环没有正常执行完(这里说的正常执行完是指没有break跳出情况,而非一些异常),那就执行else块。实际上刚好相反——在循环里用break语句提前跳出,会导致程序不执行else块,就像下面的例子:
for i in range(3):
print("Loop {}".format(i))
if i == 1:
break
else:
print("Else Block!")
# Loop 0
# Loop 1
还有,如果for循环要遍历的序列是空的,那么就会立刻执行else块:
for i in []:
print("Never Runs")
else:
print("Else Block!")
# Else Block!
初始循环条件为false的while循环,如果后面跟着else块,那么它也会立刻执行:
while False:
print("Never Runs")
else:
print("Else Block!")
# Else Block!
知道了循环后面的else块所表现出的行为后,我们会发现:在搜索某个事物的时候,这种 for/else 或 while/else 结构的写法是有意义的。比如,要判断两个数是否互质(也就是判断两者除了1之外,是否没有其他的公约数),可以把有可能成为公约数的每个值都遍历一遍,逐个判断两束时候能以该值为公约数,尝试完每一种可能的值后,循环就结束了。如果两个数确实互质,那么在循环过程中,程序就不会因break语句而跳出,于是,执行完循环后,程序会紧接着执行else块。
num1 = 4
num2 = 9
for i in range(2, min(num1, num2) + 1):
print("Testing", i)
if num1 % i == 0 and num2 % i == 0:
print("Not coprime")
break
else:
print("Coprime")
# Testing 2
# Testing 3
# Testing 4
# Coprime
事实上,我们不会这么写代码,而是使用辅助函数来完成计算,比如,只要发现受测参数符合自己想要搜索的条件,就尽早返回。如果整个循环都执行了一遍,那就说明,受测参数不符合条件,于是返回默认值。
def coprime(num1, num2):
for i in range(2, min(num1, num2) + 1):
if num1 % i == 0 and num2 % i == 0:
return False
return True
或者,用变量记录受测参数是否符合条件,一旦符合,就用break跳出循环。
def coprime(num1, num2):
is_coprime = True
for i in range(2, min(num1, num2) + 1):
if num1 % i == 0 and num2 % i == 0:
is_coprime = False
break
return is_coprime
对不熟悉 for/else 的人来说,后面这两种写法都要比 for/else 的写法清晰很多。for/else 中的else块确实能实现相应的功能,但捡来回顾这段程序的时候,却会令阅读代码的人(包括写代码的人)感到相当费解。像循环这种简单的语言结构,在Python中应当写的相当直白才对,别整那些花里胡哨的,也许只有你自己觉得 for/else 看起来高大上,这可不算炫技。所以,我们完全不应该在循环后使用else块。
- Python 提供了这种特殊语法,在for 或者 while 循环的内部语句块之后紧跟着 else 块。
- 只有当整个循环主体没有遇到break语句时,循环后的else块才会执行。
- 不要在循环后使用else块,因为这种写法既不直观,又容易引人误解。