第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个有效方法》,仅作为个人学习使用,如有侵权请告知,将及时删除,如果觉得有益,请购买原版书籍,知识需要传递和支持,谢谢。