让你的Python代码优雅又地道

让你的Python代码优雅又地道_第1张图片

Python社区文化的浇灌下,演化出了一种独特的代码风格,去指导如何正确地使用Python,这就是常说的pythonic。一般说地道(idiomatic)的python代码,就是指这份代码很pythonic。Python的语法和标准库设计,处处契合着pythonic的思想。而且Python社区十分注重编码风格一的一致性,他们极力推行和处处实践着pythonic。所以经常能看到基于某份代码P vs NP (pythonic vs non-pythonic)的讨论。pythonic的代码简练,明确,优雅,绝大部分时候执行效率高。阅读pythonic的代码能体会到“代码是写给人看的,只是顺便让机器能运行”畅快。

然而什么是pythonic,就像什么是地道的汉语一样,切实存在但标准模糊。import this可以看到Tim Peters提出的Python之禅,它提供了指导思想。许多初学者都看过它,深深赞同它的理念,但是实践起来又无从下手。PEP 8给出的不过是编码规范,对于实践pythonic还远远不够。如果你正被如何写出pythonic的代码而困扰,或许这份笔记能给你帮助。

Raymond Hettinger是Python核心开发者,本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师,不遗余力地传授pythonic之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。

术语澄清:本文所说的集合全都指collection,而不是set

以下是正文。

示例代码和引用的语录都来自Raymond的演讲。这是我按我的理解整理出来的,希望你们理解起来跟我一样顺畅 !

加vx:tanzhouyiwan 或qq群813622576免费领取Python学习资料

遍历一个范围内的数字

更好的方法

xrange会返回一个迭代器,用来一次一个值地遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range

遍历一个集合

让你的Python代码优雅又地道_第2张图片

更好的方法

反向遍历

让你的Python代码优雅又地道_第3张图片

更好的方法

遍历一个集合及其下标

让你的Python代码优雅又地道_第4张图片

更好的方法

让你的Python代码优雅又地道_第5张图片

这种写法效率高,优雅,而且帮你省去亲自创建和自增下标。当你发现你在操作集合的下标时,你很有可能在做错事。

遍历两个集合

让你的Python代码优雅又地道_第6张图片

更好的方法

zip在内存中生成一个新的列表,需要更多的内存。izipzip效率更高。

注意:在Python 3中,izip改名为zip,并替换了原来的zip成为内置函数。

有序地遍历

让你的Python代码优雅又地道_第7张图片

自定义排序顺序

让你的Python代码优雅又地道_第8张图片

更好的方法

第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。

调用一个函数直到遇到标记值

让你的Python代码优雅又地道_第9张图片

更好的方法

让你的Python代码优雅又地道_第10张图片

iter接受两个参数。第一个是你反复调用的函数,第二个是标记值。

译注:这个例子里不太能看出来方法二的优势,甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器,迭代器能用在各种地方,setsortedminmaxheapqsum……

在循环内识别多个退出点

让你的Python代码优雅又地道_第11张图片

更好的方法

让你的Python代码优雅又地道_第12张图片

for执行完所有的循环后就会执行else

译注:刚了解for-else语法时会困惑,什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if,当for后面的条件为False时执行else。其实条件为False时,就是for循环没被break出去,把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak,当for没有被break,那么循环结束时会进入到else

遍历字典的key

让你的Python代码优雅又地道_第13张图片

什么时候应该使用第二种而不是第一种方法?当你需要修改字典的时候。

如果你在迭代一个东西的时候修改它,那就是在冒天下之大不韪,接下来发生什么都活该。

d.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。

注意:如果在Python 3里迭代一个字典你得显示地写:list(d.keys()),因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。

遍历一个字典的key和value

让你的Python代码优雅又地道_第14张图片

更好的方法

让你的Python代码优雅又地道_第15张图片

iteritems()更好是因为它返回了一个迭代器。

注意:Python 3已经没有iteritems()了,items()的行为和iteritems()很接近。详情请看文档。

用key-value对构建字典

让你的Python代码优雅又地道_第16张图片

Python 3:d = dict(zip(names, colors))

用字典计数

让你的Python代码优雅又地道_第17张图片

更好的方法

让你的Python代码优雅又地道_第18张图片

用字典分组 — 第I部分和第II部分

让你的Python代码优雅又地道_第19张图片

更好的方法

让你的Python代码优雅又地道_第20张图片

字典的popitem()是原子的吗?

让你的Python代码优雅又地道_第21张图片

popitem是原子的,所以多线程的时候没必要用锁包着它。

连接字典

更好的方法

ChainMap在Python 3中加入。高效而优雅。

提高可读性

位置参数和下标很漂亮

但关键字和名称更好

第一种方法对计算机来说很便利

第二种方法和人类思考方式一致

用关键字参数提高函数调用的可读性

更好的方法

第二种方法稍微(微秒级)慢一点,但为了代码的可读性和开发时间,值得。

用namedtuple提高多个返回值的可读性

让你的Python代码优雅又地道_第22张图片

更好的方法

让你的Python代码优雅又地道_第23张图片

namedtupletuple的子类,所以仍适用正常的元组操作,但它更友好。

创建一个nametuple

unpack序列

让你的Python代码优雅又地道_第24张图片

更好的方法

第二种方法用了unpack元组,更快,可读性更好。

更新多个变量的状态

让你的Python代码优雅又地道_第25张图片

更好的方法

让你的Python代码优雅又地道_第26张图片

第一种方法的问题

x和y是状态,状态应该在一次操作中更新,分几行的话状态会互相对不上,这经常是bug的源头。

操作有顺序要求

太底层太细节

第二种方法抽象层级更高,没有操作顺序出错的风险而且更效率更高。

同时状态更新

让你的Python代码优雅又地道_第27张图片

更好的方法

让你的Python代码优雅又地道_第28张图片

效率

优化的基本原则

除非必要,别无故移动数据

稍微注意一下用线性的操作取代O(n**2)的操作

总的来说,不要无故移动数据

连接字符串

让你的Python代码优雅又地道_第29张图片

更好的方法

更新序列

让你的Python代码优雅又地道_第30张图片

更好的方法

让你的Python代码优雅又地道_第31张图片

装饰器和上下文管理

用于把业务和管理的逻辑分开

分解代码和提高代码重用性的干净优雅的好工具

起个好名字很关键

记住蜘蛛侠的格言:能力越大,责任越大

使用装饰器分离出管理逻辑

让你的Python代码优雅又地道_第32张图片

更好的方法

注意:Python 3.2开始加入了functools.lru_cache解决这个问题。

分离临时上下文

让你的Python代码优雅又地道_第33张图片

更好的方法

让你的Python代码优雅又地道_第34张图片

译注:示例代码在使用标准库decimal,这个库已经实现好了localcontext

如何打开关闭文件

让你的Python代码优雅又地道_第35张图片

更好的方法

如何使用锁

让你的Python代码优雅又地道_第36张图片

更好的方法

让你的Python代码优雅又地道_第37张图片

分离出临时的上下文

让你的Python代码优雅又地道_第38张图片

更好的方法

ignored是Python 3.4加入的, 文档。

注意:ignored实际上在标准库叫suppress(译注:contextlib.supress).

试试创建你自己的ignored上下文管理器。

让你的Python代码优雅又地道_第39张图片

把它放在你的工具目录,你也可以忽略异常

译注:contextmanager在标准库contextlib中,通过装饰生成器函数,省去用__enter____exit__写上下文管理器。详情请看文档。

分离临时上下文

让你的Python代码优雅又地道_第40张图片

更好的写法

让你的Python代码优雅又地道_第41张图片

redirect_stdout在Python 3.4加入(译注:contextlib.redirect_stdout), bug反馈。

实现你自己的redirect_stdout上下文管理器。

让你的Python代码优雅又地道_第42张图片

简洁的单句表达

两个冲突的原则:

一行不要有太多逻辑

不要把单一的想法拆分成多个部分

Raymond的原则:

一行代码的逻辑等价于一句自然语言

列表解析和生成器

让你的Python代码优雅又地道_第43张图片

更好的方法

第一种方法说的是你在做什么,第二种方法说的是你想要什么。

加vx:tanxzhouyiwan 或qq群813622576免费领取Python学习资料

让你的Python代码优雅又地道_第44张图片

你可能感兴趣的:(让你的Python代码优雅又地道)