为什么《Dive into Python》不值得推荐

本文分析了《DiveIntoPython》一书不值得推荐的原因,包括基于老版本Python编写、内容编排不当、缺乏大局观等问题,并推荐了官方教程作为替代。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2010 年 5 月 5 日更新:我翻译了一篇《<Dive Into Python>非死不可》作为对本文观点的进一步支持和对评论的回复,请见:http://blog.youkuaiyun.com/lanphaday/archive/2010/05/05/5558617.aspx

为什么《Dive into Python》不值得推荐

作者:赖勇浩(http://blog.youkuaiyun.com/lanphaday

不论是在国内人气最旺的 Python 社区 python-cn google group,还是在 优快云 的脚本论坛,都不时有新加入的朋友咨询有没有什么 Python 书比较好,回复的贴子里,肯定少不了《Dive into Python》(以下简写为 DIP,且不加书名号)。今天我要说的是它不值得推荐的理由:它太旧了,而且内容编排相当古怪,全书来看缺乏大局观,我没见认是靠它入门的,最后还有非常重要的一点——推荐者可能根本不在工作中使用 Python。

基于老版本

在第一章,我们可以看到这本书基于 Python 2.2 或 2.3 版本编写。当前 Python 最新的发布版是 2.5.2,2.6/3.0 版本也计划在今年 10 月发布,这当中相隔的版本太大,使得很多书中推荐的编码形式、性能要点都不再成立了。

其实这本书作者到 2004 年就没有再做更新了,时隔四年,对于一个开源的脚本语言来说,产生的变化足以用山河变换来形容。在 manuals 中可以看到许多特性都加 new in 2.3/2.4/2.5 的注脚,不客气地说,DIP 已经不合时宜了。

来个例子

写这篇文章的时候,我参考啄木鸟网站的DIP 5.4b 版本(http://www.woodpecker.org.cn/diveintopython/index.html ),这是 DIP 最新的中文版。其中第2章的例2.1,如下:

这里至少有两处没有充分利用新版本特性,一处是 myParams 的定义,续行符让代码变得丑陋,另一处是 join() 函数的实参无须构建一个新的列表,损失了性能。

这本书里不仅没有 new-style class,也没有function decorator;没有谈有用 Unicode 字符串,却有 UserDict 这样的老掉牙的实现。除了这此跟不上时代以外,还有一些内置函数、标准库都没有使用最新的。当 DIP 先入为主,读者会认为代码就应该这样写,以致出现大虾不识 enumerate() 的情况屡见不鲜。s

内容编排古怪

DIP 的第一个例子(即上文的例2.1)足足花了两章才能够完全说明。其中至少有如下概念:函数定义、变量定义、docstrings、字符串、字符串格式化、字典、字典迭代、列表、列表包含、元组、分枝语句、循环语句、程序入口、预定义系统变量等。哦,天啊!这是一本定位于初学者的书的第一个例子吗?而你竟然还向初学者推荐?我非常怀疑你对 DIP 一书是否真的足够了解,有没有深入地读一下这本书。

虽然我很钦佩作者竟然能找到一个如此精妙的例子,短短几行代码竟然包括了十余个 Python 特性,另外还有隐含的对数据库知识的了解。Coooooooool!但这种酷例子只会把大部分初学者吓得退避三舍。

除了这个例子外,再举一个内容编排古怪的例子——就是第4章“自省的威力”。第3章刚讲完了内置数据类型,加上第2章的基本语法、函数定义等内容,马上就应该到 Python 的特点之一:面向对象了吧?作者他偏不,读着读着,只是奇峰突起,来了个神也怪也的“自省”。如此大起大落、婉转曲折,作者应该去写章回小说,何必来写个教程凑热闹。硬着头皮读下去,发现例4.1是一个有更多 Python 特性的小例子,不知又有多少初学者在此打道回府?

缺乏大局观

大家知道一篇好文章,需要一条主线,所有的情节都是为主线服务的。写一本书也差不多,内容应当为主题服务,既然书名定为 Dive into Python,那自然应该多讲讲 Python 的知识点。但全书的第7到12 章三分之一的篇幅讲了正则表达式、HTML、XML、HTTP web 甚至 SOAP web等具体应用,而且相当多内容是与 Python 无关的、独立的协议的讲解。哦,那您老还不如写本书叫《Python 与 web 开发从入门到精通》。

这本书缺乏大局观的另一个表现在于它花了中间的三分之一的篇幅讲 web 之后,最后三分之一的内容却又开始阳春白雪起来,完全抛弃了 web 相关的内容开讲单元测试、测试驱动开发、重构、函数式编程、性能优化等主题。不得不说这些话题非常有意思,但一堆松散的珍珠并不能让你光芒四射,只有用一条金钱把它们穿起来,形成一体,才能彼此相得益彰。

一个国内 Python 社区颇有声名的高手如此评价 DIP:“我觉得 DP 最大的问题是该讲的没讲, 不该讲的乱讲。”在一本有着许多发光点的书也许可以让读者开拓眼界,但也往往导致他们变得眼高手低。以为自己什么都见过,真正开干却又无从下手。Python 是拿来用的,应当多介绍常用的模块,DIP 则是一本看完以后没法用的书。

推荐者,你靠它入了门?

好吧,这本书从 2000 年到2008 年的今天已经走过了 9 个年头,不知道多少人靠它入门了?我没有做过统计,只能在下文讲讲我掌握的情况;但读者您不妨在文章后面匿名留言,看看比较大众化的情况。

我之前在一个使用 Python 相当普及的公司任职,在入职之后才学的 Python。因为我是通过校园招聘进去的,所以同时去的有一大批应届生,几乎全部不懂 Python。后来我们也没有使用 DIP,当然,我们都学会了 Python。跟老员工熟悉了之后,加上后来在公司呆的几年,了解到公司几乎没有人用这本书。

虽然后来在网络结识了许多 Pythoner,但也仍然没有听过谁是靠 DIP 学会 Python 的。这样的事实让人不得不怀疑大家对 DIP 推荐有加其实只是以讹传讹。s

推荐者,你靠 Python 谋生吗?

像 google 的pagerank 算法,推荐 DIP 的人本身靠 Python 谋生的话,才会有说服力。我当然不知道推荐 DIP 的人是否真的靠 Python 谋生,但我这个不推荐 DIP 的人却正是靠 Python 谋生。

专业的人才能有专业的推荐,如果推荐者在本职工作中并不使用 Python,那它的推荐就像一个内蒙古人推荐的帆船,夏威夷的性感沙滩妹推荐的马,你觉得信得过吗?

我们可以不读 DIP 仍然弄懂 Python,起码说明了 DIP 并非必读书目,你不必因为曾经被 DIP 吓退而放弃 Python,我们完全有更好的选择。

那什么更好?

指出一样事物的不足不是难事,难事是推荐一个替代品。DIP 的替代品是 Python manuals 中自带的 Tutorial,甚至你仍然可以找到它的中译版。Tutorial 的好处包含但不限于以下几点:

1) 它是最新的,而且会在出新版本的时候第一时间更新;

2) 它是官方的,出自 Guido 和其他 Python 主力开发者之手,没有人比他们更有能力带你 Dive into Python,不是吗?

3) 它的内容编排循序渐进,行文平实,读起来虽然没有跌荡起伏的快感,但可以让你轻松上路;

4) 它的内容覆盖面广,这一点远胜 DIP;

5) 我和我的大部分同事都是靠它走入了 Python 的殿堂,所以这是真正的实践者的推荐;

6) 许多我认识的靠 Python程序员跟我一样认为这才是真正的好教程,当然,他们靠 Python 谋生或曾靠 Python 谋生。

如果你非要找一本可以捧在手上的书,那么一本好的 Python 书的标准是要么在广度上有建树要么就是深度。广度上来说,《Python编程金典》做得不错;深度上, 《python cookbook》和《可爱的 Python》系列文章比较好。而DIP 这种四不像让人看完后只会更迷惑,因为 Python 是拿来用的, 所以深度和广度是比较重要的。而 DIP 以入门为幌子,但是不像“金典”具有极高的可操作性。如果难以动手操作,自然不能很好地掌握知识,那么作为入门书也就变成扯淡了。

目录 1. 安装 Python 1.1. 哪一种 Python 适合您? 1.2. Windows 上的 Python 1.3. Mac OS X 上的 Python 1.4. Mac OS 9 上的 Python 1.5. RedHat Linux 上的 Python 1.6. Debian GNU/Linux 上的 Python 1.7. 从源代码安装 Python 1.8. 使用 Python 的交互 Shell 1.9. 小结 2. 第一个 Python 程序 2.1. 概览 2.2. 函数声明 2.2.1. Python 和其他编程语言数据类型的比较 2.3. 文档化函数 2.4. 万物皆对象 2.4.1. 模块导入的搜索路径 2.4.2. 何谓对象? 2.5. 代码缩进 2.6. 测试模块 3. 内置数据类型 3.1. Dictionary 介绍 3.1.1. Dictionary 的定义 3.1.2. Dictionary 的修改 3.1.3. 从 dictionary 中删除元素 3.2. List 介绍 3.2.1. List 的定义 3.2.2. 向 list 中增加元素 3.2.3. 在 list 中搜索 3.2.4. 从 list 中删除元素 3.2.5. 使用 list 的运算符 3.3. Tuple 介绍 3.4. 变量声明 3.4.1. 变量引用 3.4.2. 一次赋多值 3.5. 格式化字符串 3.6. 映射 list 3.7. 连接 list 与分割字符串 3.7.1. 字符串方法的历史注解 3.8. 小结 4. 自省的威力 4.1. 概览 4.2. 使用可选参数和命名参数 4.3. 使用 type、str、dir 和其它内置函数 4.3.1. type 函数 4.3.2. str 函数 4.3.3. 内置函数 4.4. 通过 getattr 获取对象引用 4.4.1. 用于模块的 getattr 4.4.2. getattr 作为一个分发者 4.5. 过滤列表 4.6. and 和 or 的特殊性质 4.6.1. 使用 and-or 技巧 4.7. 使用 lambda 函数 4.7.1. 真实世界中的 lambda 函数 4.8. 全部放在一起 4.9. 小结 5. 对象和面向对象 5.1. 概览 5.2. 使用 from module import 导入模块 5.3. 类的定义 5.3.1. 初始化并开始类编码 5.3.2. 了解何时去使用 self 和 __init__ 5.4. 类的实例化 5.4.1. 垃圾回收 5.5. 探索 UserDict:一个封装类 5.6. 专用类方法 5.6.1. 获得和设置数据项 5.7. 高级专用类方法 5.8. 类属性介绍 5.9. 私有函数 5.10. 小结 6. 异常和文件处理 6.1. 异常处理 6.1.1. 为其他用途使用异常 6.2. 与文件对象共事 6.2.1. 读取文件 6.2.2. 关闭文件 6.2.3. 处理 I/O 错误 6.2.4. 写入文件 6.3. for 循环 6.4. 使用 sys.modules 6.5. 与目录共事 6.6. 全部放在一起 6.7. 小结 7. 正则表达式 7.1. 概览 7.2. 个案研究:街道地址 7.3. 个案研究:罗马字母 7.3.1. 校验千位数 7.3.2. 校验百位数 7.4. 使用 {n,m} 语法 7.4.1. 校验十位数和个位数 7.5. 松散正则表达式 7.6. 个案研究:解析电话号码 7.7. 小结 8. HTML 处理 8.1. 概览 8.2. sgmllib.py 介绍 8.3. 从 HTML 文档中提取数据 8.4. BaseHTMLProcessor.py 介绍 8.5. locals 和 globals 8.6. 基于 dictionary 的字符串格式化 8.7. 给属性值加引号 8.8. dialect.py 介绍 8.9. 全部放在一起 8.10. 小结 9. XML 处理 9.1. 概览 9.2. 包 9.3. XML 解析 9.4. Unicode 9.5. 搜索元素 9.6. 访问元素属性 9.7. Segue 10. 脚本和流 10.1. 抽象输入源 10.2. 标准输入、输出和错误 10.3. 查询缓冲节点 10.4. 查找节点的直接子节点 10.5. 根据节点类型创建同的处理器 10.6. 处理命令行参数 10.7. 全部放在一起 10.8. 小结 11. HTTP Web 服务 11.1. 概览 11.2. 避免通过 HTTP 重复地获取数据 11.3. HTTP 的特性 11.3.1. 用户代理 (User-Agent) 11.3.2. 重定向 (Redirects) 11.3.3. Last-Modified/If-Modified-Since 11.3.4. ETag/If-None-Match 11.3.5. 压缩 (Compression) 11.4. 调试 HTTP web 服务 11.5. 设置 User-Agent 11.6. 处理 Last-Modified 和 ETag 11.7. 处理重定向 11.8. 处理压缩数据 11.9. 全部放在一起 11.10. 小结 12. SOAP Web 服务 12.1. 概览 12.2. 安装 SOAP 库 12.2.1. 安装 PyXML 12.2.2. 安装 fpconst 12.2.3. 安装 SOAPpy 12.3. 步入 SOAP 12.4. SOAP 网络服务查错 12.5. WSDL 介绍 12.6. 以 WSDL 进行 SOAP 内省 12.7. 搜索 Google 12.8. SOAP 网络服务故障排除 12.9. 小结 13. 单元测试 13.1. 罗马数字程序介绍 II 13.2. 深入 13.3. romantest.py 介绍 13.4. 正面测试 (Testing for success) 13.5. 负面测试 (Testing for failure) 13.6. 完备性检测 (Testing for sanity) 14. 测试优先编程 14.1. roman.py, 第 1 阶段 14.2. roman.py, 第 2 阶段 14.3. roman.py, 第 3 阶段 14.4. roman.py, 第 4 阶段 14.5. roman.py, 第 5 阶段 15. 重构 15.1. 处理 bugs 15.2. 应对需求变化 15.3. 重构 15.4. 后记 15.5. 小结 16. 函数编程 16.1. 概览 16.2. 找到路径 16.3. 重识列表过滤 16.4. 重识列表映射 16.5. 数据中心思想编程 16.6. 动态导入模块 16.7. 全部放在一起 16.8. 小结 17. 动态函数 17.1. 概览 17.2. plural.py, 第 1 阶段 17.3. plural.py, 第 2 阶段 17.4. plural.py, 第 3 阶段 17.5. plural.py, 第 4 阶段 17.6. plural.py, 第 5 阶段 17.7. plural.py, 第 6 阶段 17.8. 小结 18. 性能优化 18.1. 概览 18.2. 使用 timeit 模块 18.3. 优化正则表达式 18.4. 优化字典查找 18.5. 优化列表操作 18.6. 优化字符串操作 18.7. 小结 A. 进一步阅读 B. 五分钟回顾 C. 技巧和窍门 D. 示例清单 E. 修订历史 F. 关于本书 G. GNU Free Documentation License G.0. Preamble G.1. Applicability and definitions G.2. Verbatim copying G.3. Copying in quantity G.4. Modifications G.5. Combining documents G.6. Collections of documents G.7. Aggregation with independent works G.8. Translation G.9. Termination G.10. Future revisions of this license G.11. How to use this License for your documents H. GNU 自由文档协议 H.0. 序 H.1. 适用范围和定义 H.2. 原样复制 H.3. 大量复制 H.4. 修改 H.5. 合并文档 H.6. 文档合集 H.7. 独立著作聚集 H.8. 翻译 H.9. 终止协议 H.10. 协议将来的修订 H.11. 如何为你的文档使用本协议 I. Python license I.A. History of the software I.B. Terms and conditions for accessing or otherwise using Python I.B.1. PSF license agreement I.B.2. BeOpen Python open source license agreement version 1 I.B.3. CNRI open source GPL-compatible license agreement I.B.4. CWI permissions statement and disclaimer J. Python 协议 J.0. 关于译文的声明 J.A. 软件的历史 J.B. 使用 Python 的条款和条件 J.B.1. PSF 协议 J.B.2. BeOpen Python 开源协议第 1 版 J.B.3. CNRI 开源 GPL 兼容协议 J.B.4. CWI 许可声明与免责声明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值