Python 中的 else详解


Posted in Python onApril 23, 2016

我们都知道 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 的应用场景!

Python 相关文章推荐
Python中统计函数运行耗时的方法
May 05 Python
python使用PIL模块实现给图片打水印的方法
May 22 Python
Python实现批量转换文件编码的方法
Jul 28 Python
在Mac OS上搭建Python的开发环境
Dec 24 Python
Python 列表(List) 的三种遍历方法实例 详解
Apr 15 Python
Python mutiprocessing多线程池pool操作示例
Jan 30 Python
python实现微信自动回复及批量添加好友功能
Jul 03 Python
django连接oracle时setting 配置方法
Aug 29 Python
Python关于反射的实例代码分享
Feb 20 Python
Python库skimage绘制二值图像代码实例
Apr 10 Python
PyQt5 控件字体样式等设置的实现
May 13 Python
用python爬虫批量下载pdf的实现
Dec 01 Python
Python 探针的实现原理
Apr 23 #Python
一键搞定python连接mysql驱动有关问题(windows版本)
Apr 23 #Python
Linux 发邮件磁盘空间监控(python)
Apr 23 #Python
web.py 十分钟创建简易博客实现代码
Apr 22 #Python
在windows下快速搭建web.py开发框架方法
Apr 22 #Python
基于python实现的抓取腾讯视频所有电影的爬虫
Apr 22 #Python
Python开发之快速搭建自动回复微信公众号功能
Apr 22 #Python
You might like
php5.3后静态绑定用法详解
2016/11/11 PHP
php一个文件搞定微信jssdk配置
2016/12/12 PHP
Laravel中validation验证 返回中文提示 全局设置的方法
2019/09/29 PHP
laravel框架语言包拓展实现方法分析
2019/11/22 PHP
js之WEB开发调试利器:Firebug 下载
2007/01/13 Javascript
动态为事件添加js代码示例
2009/02/15 Javascript
jQuery如何取id有.的值一般的方法是取不到的
2014/04/18 Javascript
js动态创建及移除div的方法
2015/06/03 Javascript
.NET微信公众号开发之创建自定义菜单
2015/07/16 Javascript
JavaScript类型系统之基本数据类型与包装类型
2016/01/06 Javascript
js判断数组key是否存在(不用循环)的简单实例
2016/08/03 Javascript
微信小程序开发经验总结(推荐)
2017/01/11 Javascript
详谈angularjs中路由页面强制更新的问题
2017/04/24 Javascript
vue 多入口文件搭建 vue多页面搭建的实例讲解
2018/03/12 Javascript
微信小程序如何获取用户头像和昵称
2019/09/23 Javascript
JavaScript实现联动菜单特效
2020/01/07 Javascript
jQuery实现聊天对话框
2020/02/08 jQuery
webpack.DefinePlugin与cross-env区别详解
2020/02/23 Javascript
javascript用defineProperty实现简单的双向绑定方法
2020/04/03 Javascript
[46:02]DOTA2上海特级锦标赛D组资格赛#2 Liquid VS VP第二局
2016/02/28 DOTA
Python的Flask框架中配置多个子域名的方法讲解
2016/06/07 Python
python实现用类读取文件数据并计算矩形面积
2020/01/18 Python
Python日志logging模块功能与用法详解
2020/04/09 Python
Keras搭建自编码器操作
2020/07/03 Python
DRF使用simple JWT身份验证的实现
2021/01/14 Python
白宫黑市官网:White House Black Market
2016/11/17 全球购物
小学生读书感言
2014/02/12 职场文书
会计助理岗位职责
2014/02/17 职场文书
互联网创业计划书写作技巧攻略
2014/03/23 职场文书
2014年销售经理工作总结
2014/12/01 职场文书
班主任经验交流材料
2014/12/16 职场文书
2015年高一班主任工作总结
2015/05/13 职场文书
爱国之歌(8首)
2019/09/29 职场文书
Python3接口性能测试实例代码
2021/06/20 Python
CentOS7安装MySQL8的超级详细教程(无坑!)
2022/06/10 Servers
python数字图像处理之图像的批量处理
2022/06/28 Python