神刀安全网

Python 无处不在的else – PyTips 0x0b

Python 无处不在的else - PyTips 0x0b
PyTips

项目地址: https://git.io/pytips

我们都知道 Python 中 else 的基本用法是在条件控制语句中的 if...elif...else... ,但是 else 还有两个其它的用途,一是用于循环的结尾,另一个是用在错误处理的 try 中。这原本是 Python 的标准语法,但由于和大部分其它编程语言的习惯不太一样,致使人们有意或无意地忽略了这些用法。另外,对于这些用法是否符合 0x00 The Zen of Python 的原则以及该不该广泛使用也存在很多争议。例如在我看到的两本书里( Effective Python VS Write Idiomatic Python ),两位作者就分别对其持有截然不同的态度。

循环中的 else

跟在循环后面的 else 语句只有在当循环内没出现 break ,也就是正常循环完成时才会执行。首先我们来看一个插入排序法的例子:

from random import randrange def insertion_sort(seq):     if len(seq) <= 1:         return seq     _sorted = seq[:1]     for i in seq[1:]:         inserted = False         for j in range(len(_sorted)):             if i < _sorted[j]:                 _sorted = [*_sorted[:j], i, *_sorted[j:]]                 inserted = True                 break         if not inserted:             _sorted.append(i)     return _sorted  print(insertion_sort([randrange(1, 100) for i in range(10)]))
[8, 12, 12, 34, 38, 68, 72, 78, 84, 90]

在这个例子中,对已排序的 _sorted 元素逐个与 i 进行比较,若 i 比已排序的所有元素都大,则只能排在已排序列表的最后。这时我们就需要一个额外的状态变量 inserted 来标记完成遍历循环还是中途被 break ,在这种情况下,我们可以用 else 来取代这一状态变量:

def insertion_sort(seq):     if len(seq) <= 1:         return seq     _sorted = seq[:1]     for i in seq[1:]:         for j in range(len(_sorted)):             if i < _sorted[j]:                 _sorted = [*_sorted[:j], i, *_sorted[j:]]                 break         else:             _sorted.append(i)     return _sorted print(insertion_sort([randrange(1, 100) for i in range(10)]))
[1, 10, 27, 32, 32, 43, 50, 55, 80, 94]

我认为这是一个非常酷的做法!不过要注意的是,除了 break 可以触发后面的 else 语句,没有循环的时候也会:

while False:     print("Will never print!") else:     print("Loop failed!")
Loop failed!

错误捕捉中的 else

try...except...else...finally 流程控制语法用于捕捉可能出现的异常并进行相应的处理,其中 except 用于捕捉 try 语句中出现的错误;而 else 则用于处理 没有出现错误 的情况; finally 负责 try 语句的”善后工作“ ,无论如何都会执行。可以通过一个简单的例子来展示:

def divide(x, y):     try:         result = x / y     except ZeroDivisionError:         print("division by 0!")     else:         print("result = {}".format(result))     finally:         print("divide finished!") divide(5,2) print("*"*20) divide(5,0)
result = 2.5 divide finished! ******************** division by 0! divide finished!

当然,也可以用状态变量的做法来替代 else

def divide(x, y):     result = None     try:         result = x / y     except ZeroDivisionError:         print("division by 0!")     if result is not None:         print("result = {}".format(result))     print("divide finished!")   divide(5,2) print("*"*20) divide(5,0)
result = 2.5 divide finished! ******************** division by 0! divide finished!

总结

有人觉得 else 的这些用法违反直觉或者是 implicit 而非 explicit ,不值得提倡。但我觉得这种”判决“需要依赖具体的应用场景以及我们对 Python 的理解,并非一定要对新人友好的语法才算是 explicit 的。当然也不推荐在所有地方都使用这个语法, for/while...else 最大的缺点在于 else 是需要与 for/file 对齐的,如果是多层嵌套或者循环体太长的情况,就非常不适合用 else (回忆一下游标卡尺的梗就知道了:P)。只有在一些简短的循环控制语句中,我们通过 else 摆脱一些累赘的状态变量,这才是最 Pythonic 的应用场景!

Python 无处不在的else - PyTips 0x0b

欢迎关注公众号 PyHub!

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Python 无处不在的else – PyTips 0x0b

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮