Python 中的 else详解
我们都知道Python中else的基本用法是在条件控制语句中的if...elif...else...,但是else还有两个其它的用途,一是用于循环的结尾,另一个是用在错误处理的try中。这原本是Python的标准语法,但由于和大部分其它编程语言的习惯不太一样,致使人们有意或无意地忽略了这些用法。另外,对于这些用法是否符合0×00TheZenofPython的原则以及该不该广泛使用也存在很多争议。例如在我看到的两本书里(EffectivePythonVSWriteIdiomaticPython),两位作者就分别对其持有截然不同的态度。
循环中的else
跟在循环后面的else语句只有在当循环内没出现break,也就是正常循环完成时才会执行。首先我们来看一个插入排序法的例子:
fromrandomimportrandrange definsertion_sort(seq): iflen(seq)1: returnseq _sorted=seq[:1] foriinseq[1:]: inserted=False forjinrange(len(_sorted)): ifi_sorted[j]: _sorted=[*_sorted[:j],i,*_sorted[j:]] inserted=True break ifnotinserted: _sorted.append(i) return_sorted print(insertion_sort([randrange(1,100)foriinrange(10)])) [8,12,12,34,38,68,72,78,84,90]
在这个例子中,对已排序的_sorted元素逐个与i进行比较,若i比已排序的所有元素都大,则只能排在已排序列表的最后。这时我们就需要一个额外的状态变量inserted来标记完成遍历循环还是中途被break,在这种情况下,我们可以用else来取代这一状态变量:
definsertion_sort(seq): iflen(seq)1: returnseq _sorted=seq[:1] foriinseq[1:]: forjinrange(len(_sorted)): ifi_sorted[j]: _sorted=[*_sorted[:j],i,*_sorted[j:]] break else: _sorted.append(i) return_sorted print(insertion_sort([randrange(1,100)foriinrange(10)])) [1,10,27,32,32,43,50,55,80,94]
我认为这是一个非常酷的做法!不过要注意的是,除了break可以触发后面的else语句,没有循环的时候也会:
whileFalse: print("Willneverprint!") else: print("Loopfailed!") Loopfailed!
错误捕捉中的else
try...except...else...finally流程控制语法用于捕捉可能出现的异常并进行相应的处理,其中except用于捕捉try语句中出现的错误;而else则用于处理没有出现错误的情况;finally负责try语句的”善后工作“,无论如何都会执行。可以通过一个简单的例子来展示:
defdivide(x,y): try: result=x/y exceptZeroDivisionError: print("divisionby0!") else: print("result={}".format(result)) finally: print("dividefinished!") divide(5,2) print("*"*20) divide(5,0)
result=2.5 dividefinished! ******************** divisionby0! dividefinished!
当然,也可以用状态变量的做法来替代else:
defdivide(x,y): result=None try: result=x/y exceptZeroDivisionError: print("divisionby0!") ifresultisnotNone: print("result={}".format(result)) print("dividefinished!") divide(5,2) print("*"*20) divide(5,0)
result=2.5 dividefinished! ******************** divisionby0! dividefinished!
总结
有人觉得else的这些用法违反直觉或者是implicit而非explicit,不值得提倡。但我觉得这种”判决“需要依赖具体的应用场景以及我们对Python的理解,并非一定要对新人友好的语法才算是explicit的。当然也不推荐在所有地方都使用这个语法,for/while...else最大的缺点在于else是需要与for/file对齐的,如果是多层嵌套或者循环体太长的情况,就非常不适合用else(回忆一下游标卡尺的梗就知道了:P)。只有在一些简短的循环控制语句中,我们通过else摆脱一些累赘的状态变量,这才是最Pythonic的应用场景!