Python 中的 else详解
作者:hebedich 发布时间:2021-12-15 09:42:18
我们都知道 Python 中else的基本用法是在条件控制语句中的 if...elif...else...,但是 else 还有两个其它的用途,一是用于循环的结尾,另一个是用在错误处理的 try 中。这原本是 Python 的标准语法,但由于和大部分其它编程语言的习惯不太一样,致使人们有意或无意地忽略了这些用法。另外,对于这些用法是否符合 0×00 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 的应用场景!


猜你喜欢
- 对很多从事产品工作的同事来说,“以用户为中心”是工作的重点,同时也是难点。用户的心思难以捉摸,用户研究的工作也似乎高深莫测。不过,用户研究并
- 运用Jmeter正则提取器,可以从请求的响应结果中取到需要的内容,从而实现关联。关联是请求与请求之间存在数据依赖关系,需要从上一个请求获取下
- 本文介绍用python实现的搜索本地文本文件内容的小程序。从而学习Python I/O方面的知识。代码如下:import os#根据文件扩展
- 试官: 听说你熟悉python,那么你能简单阐述一下python的装饰器、生成器以及迭代器么?我: emm, 我不清楚,我只是了解过pyth
- 之前,我曾转过一个单元测试框架系列的文章,里面介绍了 unittest、nose/nose2 与 pytest 这三个最受人欢迎的 Pyth
- 在做DHTML时,我们在某些情况下要用setAttribute(attri, value)方法定义元素的attribute。同时与getAt
- Jupyter Notebook默认不显示行号,可是当我们代码报错时,发现会显示自己多少行出现错误。eg:这时候我们总不能一行行去数吧,因此
- 加了三个验证漏洞以及四个getshell方法# /usr/bin/env python3# -*- coding: utf-8 -*-# @
- mysql升级5.7版本以后,安全性大幅度上升。但是呢。。。带复杂的记不住。额额。。本来脑子就不好使,还记那么复杂,尤其是本地就更没必要,还
- 问题重现Installing golang.org/x/tools/cmd/guru FAILED Installing golang.or
- 这篇文章主要介绍了python文字和unicode/ascll相互转换函数及简单加密解密实现代码,下面我们来了解一下。import reim
- 一.基本数据类型整数:int字符串:str(注:\t等于一个tab键)布尔值: bool列表:list 列表用[]元祖:tuple元祖用()
- 1.前言选项(Options)模式是对配置(Configuration)的功能的延伸。在12章(ASP.NET Core中的配置二)Conf
- 为了使一个MySQL系统安全,强烈要求你考虑下列建议……当你连接一个MySQL服务器时,你通常应
- 代码如下:'个人代码风格注释(变量名中第一个小写字母表表示变量类型) 'i:为Integer型; 's:为Strin
- 第一部分:判断两张图片是否相同要查找重复的图片,必然绕不开判断两张图片是否相同。判断两张图片简单呀!图片可以看成数组,比较两个数组是否相等不
- 移动互联网被称为“第五次科技革命”,而随着iPhone和Android等智能手机的日渐流行和iPad等平板电脑的出现,移动互联网的潜力和趋势
- DDPDistributed Data Parallel 简称 DDP,是 PyTorch 框架下一种适用于单机多卡、多机多卡任务的数据并行
- 1、画直线的函数是cv2.linecv2.line函数语法:cv2.line(img,start_point,end_point,color
- 1、Config命令Config命令主要用于修改SSI的默认设置。其中:Errmsg:设置默认错误信息。为了能够正常的返回用户设定的错误信息