- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议1:理解 Pythonic 概念
什么是Pythonic?这是很难定义的,这就是为什么大家无法通过搜索引擎找到准确答案的原因。但很难定义的概念绝非意味着其定义没有价值,尤其不能否定它对编写优美的Python代码的指导作用。
对于Pythonic的概念,众人各有自己的看法,但大家心目之中都认同一个更具体的指南,那就是Tim Peters的《The Zen of Python》(Python之禅)。在这一充满着禅意的诗篇中,有几点非常深入人心:
美胜丑,显胜隐,简胜杂,杂胜乱,平胜陡,疏胜密。
找到简单问题的一个方法,最好是唯一的方法(正确的解决之道)。
难以解释的实现,源自不好的主意;如有非常棒的主意,它的实现肯定易于解释。
不仅这几点,其实《Python之禅》中的每一句都可作为编程的信条。是的,不仅是作为编写Python代码的信条,以它为信条编写出的其他语言的代码也会非常漂亮。
(1)Pythonic的定义
遵循Pythonic的代码,看起来就像是伪代码。其实,所有的伪代码都可以轻易地转换为可执行的Python代码。比如在Wikipedia的快速排序 [1]条目中有如下伪代码:
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 concatenate(quicksort('less'), list('pivot'), quicksort('greater')) // two recursive calls
实际上,它可以转化为以下同等行数的可以执行的Python代码:
def quicksort(array): less = []; greater = [] if len(array) <= 1: return array pivot = array.pop() for x in array: if x <= pivot: less.append(x) else: greater.append(x) return quicksort(less)+[pivot]+quicksort(greater)
看,行数一样的Python代码甚至可读性比伪代码还要好吧?但它真的可以运行,结果如下:
>>>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的packaging/unpackaging机制,Pythonic的代码只需要以下一行:
a, b = b, a
还有,在遍历一个容器的时候,类似其他编程语言的代码如下:
length = len(alist) i = 0 while i < length: do_sth_with(alist[i]) i += 1
而 Pythonic的代码如下:
for i in alist: do_sth_with(i)
灵活地使用迭代器是一种Python风格。又比如,需要安全地关闭文件描述符,可以使用以下with语句:
with open(path, 'r') as f: do_sth_with(f)
通过上述代码的对比,能让大家清晰地认识到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 list(reversed(a)) print list(reversed(c))
(3)标准库
写Pythonic程序需要对标准库有充分的理解,特别是内置函数和内置数据类型。比如,对于字符串格式化,一般这样写:
print 'Hello %s!' % ('Tom',)
其实%s是非常影响可读性的,因为数量多了以后,很难清楚哪一个占位符对应哪一个实参。所以相对应的Pythonic代码是这样的:
print 'Hello %(name)s!' % {'name': 'Tom'}
这样在参数比较多的情况下尤其有用。
# 字符串 value = {'greet': 'Hello world', 'language': 'Python'} print '%(greet)s from %(language)s.' % value
%占位符来自于大家的先验知识,其实对于新手而言,有点“莫名其妙”,所以更具有Pythonic风格的代码如下:
print '{greet} from {language}.'.format(greet = '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文件。
[1] http://en.wikipedia.org/wiki/Quicksort。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论