![Effective Python:编写高质量Python代码的90个有效方法(原书第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/417/39980417/b_39980417.jpg)
第9条 不要在for与while循环后面写else块
Python的循环有一项大多数编程语言都不支持的特性,即可以把else
块紧跟在整个循环结构的后面。
![047-01](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/047-01.jpg?sign=1738891099-hcmM8xRlhdYK9F6i4LAU52OBJAT0JgwT-0-c488dabef83c7c3bbd62d96e352cc9b7)
奇怪的是,程序做完整个for
循环之后,竟然会执行else
块里的内容。既然是这样,那为什么要叫“else”呢?这应该叫“and”才对。在if/else
结构里,else
的意思是:如果没执行前面那块语句,那就执行else
块。在try/except
结构里,except
也是这个意思:如果前面那块语句执行失败,那就执行except
块。
try/except/else
结构里的else
依然遵循这样的理念(参见第65条),它的意思是:如果没有异常需要处理,那就执行这块语句。try/finally
结构里的finally
同样很直观,意思是:不管前面那块代码执行得如何,最后都要执行finally
块代码。
了解了else
、except
、finally
等在上面那些结构里的用法,Python新手可能就觉得,for/else
结构里的else
也是这个意思,即如果循环没有从头到尾执行完,那就执行else
块。实际上恰恰相反,如果循环没有从头到尾执行完(也就是循环提前终止了),那么else
块里的代码是不会执行的。在循环中使用break
语句实际上会跳过else
块。
![047-02](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/047-02.jpg?sign=1738891099-TTeyuMpPzzbxvuaBp4kW1wVRFTJiMrC2-0-6663c99c5dccd2195dce7ef2468cb656)
还有一个奇怪的地方是,如果对空白序列做for
循环,那么程序立刻就会执行else
块。
![047-03](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/047-03.jpg?sign=1738891099-N2rHD9qFlfvDL3Pfb39u1s3vfN2BuN7r-0-b65632c890a42b09716ad4d3974add88)
while
循环也是这样,如果首次循环就遇到False
,那么程序也会立刻运行else
块。
![047-04](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/047-04.jpg?sign=1738891099-sUpBww9peqiNMvVSjqBwE2iMHpsZEQJL-0-d8c30e87ec6f544ed121570880f23e48)
把else
设计成这样,是想让你利用它实现搜索逻辑。例如,如果要判断两个数是否互质(也就是除了1之外,是不是没有别的数能够同时整除它们),就可以用这种结构实现。先把有可能同时整除它们的数逐个试一遍,如果全都试过之后还是没找到这样的数,那么循环就会从头到尾执行完(这意味着循环没有因为break
而提前跳出),然后程序就会执行else
块里的代码。
![048-01](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/048-01.jpg?sign=1738891099-KpRQC46YRu5JUKDUzHFuQVeMCUSqwWM8-0-345ece05d68122005957d962e8346a79)
实际工作中,笔者不会这样写,而是会改用辅助函数完成计算。这样的辅助函数有两种常见的写法。
第一种写法是,只要发现某个条件成立,就立刻返回,如果始终都没碰到这种情况,那么循环就会完整地执行,让程序返回函数末尾的那个值作为默认返回值。
![048-02](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/048-02.jpg?sign=1738891099-28yeYsRzUGhUcemutmXQE9plnipZ1Jpx-0-2f50b51e9b11c3fd83b14174f75957a6)
第二种写法是,用变量来记录循环过程中有没有碰到这样的情况,如果有,那就用break
提前跳出循环,如果没有,循环就会完整地执行,无论如何,最后都返回这个变量的值。
![048-03](https://epubservercos.yuewen.com/873E3D/20818200901954706/epubprivate/OEBPS/Images/048-03.jpg?sign=1738891099-V9yImMYThodOGgb43qqHsO2s7G8ZXphx-0-fab97da3af82eb298cc60f1117c605c0)
对于不熟悉for/else
结构的人来说,刚才那两种写法都是比较清晰的方案,大家可以根据情况选择其中的一种。for/else
或while/else
结构本身虽然可以实现某些逻辑表达,但它给读者(也包括你自己)带来的困惑,已经盖过了它的好处。因为for
与while
循环这种简单的结构,在Python里面读起来应该相当明了才对,如果把else
块紧跟在它的后面,那就会让代码产生歧义。所以,请不要这么写。
要点
- Python有种特殊的语法,可以把
else
块紧跟在整个for
循环或while
循环的后面。 - 只有在整个循环没有因为
break
提前跳出的情况下,else
块才会执行。 - 把
else
块紧跟在整个循环后面,会让人不太容易看出这段代码的意思,所以要避免这样写。