我们都知道 Python 中else的基本用法是在条件控制语句中的 if...elif...else...,但是 else 还有两个其它的用途,一是用于循环的结尾,另一个是用在错误处理的 try 中。这原本是 Python 的标准语法,但由于和大部分其它编程语言的习惯不太一样,致使人们有意或无意地忽略了这些用法。另外,对于这些用法是否符合 0×00 The Zen of Python 的原则以及该不该广泛使用也存在很多争议。例如在我看到的两本书里(Effective Python VS Write Idiomatic Python),两位作者就分别对其持有截然不同的态度。
循环中的 else
跟在循环后面的 else 语句只有在当循环内没出现 break,也就是正常循环完成时才会执行。首先我们来看一个插入排序法的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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 来取代这一状态变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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 语句,没有循环的时候也会:
1
2
3
4
5
6
7
|
while False :
print ( "Will never print!" )
else :
print ( "Loop failed!" )
Loop failed!
|
错误捕捉中的 else
try...except...else...finally 流程控制语法用于捕捉可能出现的异常并进行相应的处理,其中 except 用于捕捉 try 语句中出现的错误;而 else 则用于处理没有出现错误的情况;finally 负责 try 语句的”善后工作“ ,无论如何都会执行。可以通过一个简单的例子来展示:
1
2
3
4
5
6
7
8
9
10
11
12
|
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 )
|
1
2
3
4
5
|
result = 2.5
divide finished!
* * * * * * * * * * * * * * * * * * * *
division by 0 !
divide finished!
|
当然,也可以用状态变量的做法来替代 else:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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 )
|
1
2
3
4
5
|
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 的应用场景!