第12条:不要在for和while循环后面写else块

核心知识点:

(1)一般的if/else是前面不执行,后面才执行,循环下面的else是前面执行完后面才会执行,如果是break打断也不会执行。循环为空或False也不执行。

(2)try/expect是前面不执行后面才会执行,try/expect/else是try执行成功才会执行else,也就是expect不执行;try/finally不管前面是否执行后面都会执行。

(3)不要在循环后面使用else,这会让人很费解。

 

 

Python提供了一种很多编程语言都不支持的功能,那就是可以在循环内部的语句后面直接编写else。

>>> for i in range(3):
...     print('Loop %d' % i)
... else:
...     print('Else block!')
...
Loop 0
Loop 1
Loop 2
Else block!

奇怪的是,这种else块会在整个循环执行完之后立刻执行。既然如此,那为什么叫做else呢?为什么不叫and?

在if/else语句中,else的意思是:如果不执行前面那个if块,那就执行else块。

在try/expect语句中,expect的定义也类似:如果前面那个try块没有成功执行,那就执行expect块。

同理,try/expect/else也是如此,该结构的else含义是:如果前面的try块没有失败,那就执行else。

try/finally的意思是:执行过前面的try块之后,总是执行finally块。

 

明白了else、expect和finally的含义之后,刚接触Python的程序员可能会把for/else结构中的else理解为:

如果循环没有正常执行完,那就执行else块。实际上刚好相反——在循环里用break语句提前跳出,会导致程序不执行else块。

>>> for i in range(3):
...     print('Loop %d' % i)
...     if i == 1:
...         break
... else:
...     print('Else block!')
...
Loop 0
Loop 1   #没有执行else

还有一个奇怪的地方:如果for循环要遍历的序列是空的,那么就会立刻执行else块。

>>> for x in []:
...     print('Never runs')
... else:
...     print('For Else block!')
...
For Else block!

初始循环条件为false的while循环,如果后面跟着else,那它也会立刻执行。

>>> while False:
...     print('Never runs')
... else:
...     print('While Else block!')
...
While Else block!

知道了循环后面的else块所表现出的行为之后,我们会发现:在搜索某个事物的时候,这种写法是有意义的。

>>> a = 4
>>> b = 9
>>> for i in range(2,min(a,b) + 1):
...     print('Testing',i)
...     if a % i == 0 and b % i == 0:
...         print('Not coprime')
...         break
... else:
...     print('Coprime')
...
Testing 2
Testing 3
Testing 4
Coprime

上面的式子可以判断两个数是否有除了1之外的公约数,如果有,则不会打印Compire,如果没有,就会打印Compire。

实际上,我们不会这样写代码,而是会用辅助函数来完成计算,这样的辅助函数有两种常见的写法。

第一种写法是,只要发现受测参数符合自己想要搜寻的条件,就尽早返回。如果整个循环都完整地执行了一遍,那就说明受测参数不符合要求,于是返回默认值。

>>> def coprime(a,b):
...     for i in range(2,min(a,b) + 1):
...         if a % i == 0 and b % i == 0:
...             return False
...     return True

第二种写法是,用变量来记录首测参数是否符合自己想要搜寻的条件。一旦符合,就用break跳出循环。

>>> def coprime2(a,b):
...     is_coprime == True
...     for i in range(2,min(a,b) + 1):
...         if a % i == 0 and b % i == 0:
...             is_coprime == False
...             breake
...     return is_coprime  #这种方法只是上面那一种方法的升级版

 

对于不熟悉for/else的人来说,这两种写法都要比早前那种写法清晰很多。

for/else结构中的else块虽然也能够实现相应的功能,但是会令阅读代码的人相当不解,因为它不是属于常规逻辑。

像循环这种简单的语言结构,在python程序中应该写得非常直白才对,我们完全不应该在循环的后面使用else块

 

 

文章摘抄于Brett Slatkin的《编写高质量Python代码的59个有效方法》,仅作为个人学习使用,如有侵权请告知,将及时删除,如果觉得有益,请购买原版书籍,知识需要传递和支持,谢谢。

posted @ 2017-12-11 23:19  明王不动心  阅读(2555)  评论(0编辑  收藏  举报