摘要:可以通过一个简单的例子来展示当然,也可以用状态变量的做法来替代总结有人觉得的这些用法违反直觉或者是而非,不值得提倡。
项目地址: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 的应用场景!
欢迎关注公众号 PyHub!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/37827.html
摘要:项目地址我之前翻译了协程原理这篇文章之后尝试用了模式下的协程进行异步开发,确实感受到协程所带来的好处至少是语法上的。 项目地址:https://git.io/pytips 我之前翻译了Python 3.5 协程原理这篇文章之后尝试用了 Tornado + Motor 模式下的协程进行异步开发,确实感受到协程所带来的好处(至少是语法上的:D)。至于协程的 async/await 语法是如...
摘要:项目地址迭代器与生成器迭代器与生成器是中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例子。生成器前面说到创建迭代器有种方法,其中第三种就是生成器。 项目地址:https://git.io/pytips 迭代器与生成器 迭代器(iterator)与生成器(generator)是 Python 中比较常用又很容易混淆的两个概念,今天就把它们梳理一遍,并举一些常用的例...
摘要:项目地址所有用过的人应该都看过下面两行错误信息这就是界的锟斤拷今天和接下来几期的内容将主要关注中的字符串字节及两者之间的相互转换。 项目地址:https://git.io/pytips 所有用过 Python (2&3)的人应该都看过下面两行错误信息: UnicodeEncodeError: ascii codec cant encode characters in position...
摘要:项目地址提供两种内置排序方法,一个是只针对的原地排序方法,另一个是针对所有可迭代对象的非原地排序方法。 项目地址:https://git.io/pytips Python 提供两种内置排序方法,一个是只针对 List 的原地(in-place)排序方法 list.sort(),另一个是针对所有可迭代对象的非原地排序方法 sorted()。 所谓原地排序是指会立即改变被排序的列表对象,就...
摘要:项目地址作为一种脚本语言,可以非常方便地用于系统尤其是系统命令行工具的开发。自身也集成了一些标准库,专门用于处理命令行相关的问题。命令行工具的一般结构标准输入输出系统中,一切皆为文件,因此标准输入输出可以完全可以看做是对文件的操作。 项目地址:https://git.io/pytips Python 作为一种脚本语言,可以非常方便地用于系统(尤其是*nix系统)命令行工具的开发。Pyt...
阅读 768·2021-11-18 10:02
阅读 2439·2021-11-11 16:54
阅读 2713·2021-09-02 09:45
阅读 631·2019-08-30 12:52
阅读 2641·2019-08-29 14:04
阅读 2715·2019-08-29 12:39
阅读 416·2019-08-29 12:27
阅读 1873·2019-08-26 13:23