第1章
引论
“罗马不是一天建成的”,编写代码水平的提升也不可能一蹴而就,通过一点一滴的积累,才能达成从量变到质变的飞跃。这种积累可以从很多方面取得,如一些语言层面的使用技巧、常见的注意事项、编程风格等。本章主要探讨Python中常见的编程准则,从而帮助读者进一步理解Pythonic的本质。本章内容包括如何编写Pythonic代码、在实际应用中需要注意的一些事项和值得提倡的一些做法。希望读者通过对本章的学习,可以在实际应用Pythonic的过程中得到启发和帮助。
建议1:理解Pythonic概念
什么是Pythonic?这是很难定义的,这就是为什么大家无法通过搜索引擎找到准确答案的原因。但很难定义的概念绝非意味着其定义没有价值,尤其不能否定它对编写优美的Python代码的指导作用。
对于Pythonic的概念,众人各有自己的看法,但大家心目之中都认同一个更具体的指南,那就是Tim Peters的《The Zen of Python》(Python之禅)。在这一充满着禅意的诗篇中,有几点非常深入人心:
美胜丑,显胜隐,简胜杂,杂胜乱,平胜陡,疏胜密。
找到简单问题的一个方法,最好是唯一的方法(正确的解决之道)。
难以解释的实现,源自不好的主意;如有非常棒的主意,它的实现肯定易于解释。
不仅这几点,其实《Python之禅》中的每一句都可作为编程的信条。是的,不仅是作为编写Python代码的信条,以它为信条编写出的其他语言的代码也会非常漂亮。
(1)Pythonic的定义
遵循Pythonic的代码,看起来就像是伪代码。其实,所有的伪代码都可以轻易地转换为可执行的Python代码。比如在Wikipedia的快速排序条目中有如下伪代码:
function quicksort''array''
if length''array'' ≤ 1
return ''array'' an array of zero or one elements is already sorted
select and remove a pivot element ''pivot'' from ''array'' see ''Choice of pivot'' below
create empty lists ''less'' and ''greater''
for each ''x'' in ''array''
if ''x'' ≤ ''pivot'' then append ''x'' to ''less''
else append ''x'' to ''greater''
return concatenatequicksort''less'', list''pivot'', quicksort''greater''
two recursive calls
实际上,它可以转化为以下同等行数的可以执行的Python代码:
def quicksortarray:
less = []; greater = []
if lenarray quicksort[9,8,4,5,32,64,2,1,0,10,19,27]
[0,1,2,4,5,8,9,10,19,27,32,64]
所以,综合这个例子来说,Pythonic也许可以定义为:充分体现Python自身特色的代码风格。接下来就看看这样的代码风格在实际中是如何体现的。
(2)代码风格
对于风格,光说是没有用的,最好是通过例子来看看,因为例子看得见,会显得更真实。下面以语法、库和应用程序为例给大家介绍。
在语法上,代码风格要充分表现Python自身特色。举个最常见的例子,在其他的语言(如C语言)中,两个变量交换需要如下的代码:
int a = 1, b = 2;
int tmp = a;
a = b;
b = tmp;
利用Python的packagingunpackaging机制,Pythonic的代码只需要以下一行:
a, b = b, a
还有,在遍历一个容器的时候,类似其他编程语言的代码如下:
length = lenalist
i = 0
while i length:
do_sth_withalist[i]
i += 1
而 Pythonic的代码如下:
for i in alist:
do_sth_withi
灵活地使用迭代器是一种Python风格。又比如,需要安全地关闭文件描述符,可以使用以下with语句:
with openpath, ''r'' as f:
do_sth_withf
通过上述代码的对比,能让大家清晰地认识到Pythonic的一个要求,就是对Python语法本身的充分发挥,写出来的代码带着Python味儿,而不是看着像C语言代码,或者Java代码。
应当追求的是充分利用Python语法,但不应当过分地使用奇技淫巧,比如利用Python的Slice语法,可以写出如下代码:
a = [1,2,3,4]
c = ''abcdef''
print a[::-1]
print c[::-1]
如果不是同样追求每一个语法细节的“老鸟”,这段代码的作用恐怕不能一眼就看出来。实际上,这个时候更好地体现Pythonic的代码是充分利用Python库里reversed函数的代码。
print listreverseda
print listreversedc
(3)标准库
写Pythonic程序需要对标准库有充分的理解,特别是内置函数和内置数据类型。比如,对于字符串格式化,一般这样写:
print ''Hello %s!'' % ''Tom'',
其实%s是非常影响可读性的,因为数量多了以后,很难清楚哪一个占位符对应哪一个实参。所以相对应的Pythonic代码是这样的:
print ''Hello %names!'' % {''name'': ''Tom''}
这样在参数比较多的情况下尤其有用。
#字符串
value = {''greet'': ''Hello world'', ''language'': ''Python''}
print ''%greets from %languages.'' % value
%占位符来自于大家的先验知识,其实对于新手而言,有点“莫名其妙”,所以更具有Pythonic风格的代码如下:
print ''{greet} from {language}.''.formatgreet = ''Hello world'', language = ''Python''
str.format方法非常清晰地表明了这条语句的意图,而且模板的使用也减少了许多不必要的字符,使可读性得到了很大的提升。事实上,str.format也成了Python最为推荐的字符串格式化方法,当然也是最Pythonic的。
(4)Pythonic的库或框架
编写应用程序的时候的要求会更高一些。因为编写应用程序一般需要团队合作,那么可能你编写的那一部分正好是团队的另一成员需要调用的接口,换言之,你可能正在编写库或框架。
程序员利用Pythonic的库或框架能更加容易、更加自然地完成任务。如果用Python编写的库或框架迫使程序员编写累赘的或不推荐的代码,那么可以说它并不Pythonic。现在业内通常认为Flask这个框架是比较Pythonic的,它的一个Hello world级别的用例如下:
from flask import Flask
app = Flask__name__
@app.route''''
def hello:
return "Hello world!"
if __name__ == "__main__":
app.run
稍有编程经验的人都可以通过上例认识到利用Python编程极为容易这一事实。一个Pythonic的框架不会对已经通过惯用法完成的东西重复发明“轮子”,而且它也遵循常用的Python惯例。创建Pythonic的框架极其困难,什么理念更酷、更符合语言习惯对此毫无帮助,事实上这些年来优秀的Python代码的特性也在不断演化。比如现在认为像generators之类的特性尤为Pythonic。
另一个有关新趋势的例子是:Python的包和模块结构日益规范化。现在的库或框架跟随了以下潮流:
包和模块的命名采用小写、单数形式,而且短小。
包通常仅作为命名空间,如只包含空的__init__.py文件。
建议2:编写Pythonic代码
如何编写更加Pythonic的代码,与定义什么是Pythonic一样困难。在这里,只能给出一些经验之谈,希望对大家有所帮助。