你是否有过这样的经历,收到一件不错的生日礼物或圣诞礼物,但是打开后却发现送你的人忘了买电池?Python的“内置电池”哲学让作为程序员的你不会遇到这类问题,只要安装了Python,就拥有了完成任何功能所需的一切条件。
然而,Python标准库的开发者并不能预测你要实现的“任何”功能到底是什么。即使可以,大多数人也不想去处理一个几个GB的文件下载,即使可能只是需要写一个重命名文件的脚本。关键在于,即使拥有所有的扩展功能,仍然有许多功能是Python标准库没有涵盖的。不过,这并不是说有些事情是根本无法用Python实现的,这只是表明有些事情可能需要使用外部库。
Python标准库是安全且范围明确的:模块文档化程度很高,并且有足够多的人在经常使用它,从而可以保证在你想使用它时肯定不会遇到麻烦。而且,就算万一出了问题,也能确保在短时间内有人解决。但是,外部库就像是地图上标着“熊出没,请注意”的部分:可能缺少文档,功能有bug,更新较少或根本不更新。任何正式的项目都可能用到一些只有外部库提供的功能,但是需要谨记使用这些外部库可能带来的风险。
下面是来自一线的案例。OpenStack使用了SQLAlchemy(<http://www.sqlalchemy.org/>)——一个Python数据库开发工具包。如果了解SQL的话会知道,数据库的结构是会发生变化的,所以OpenStack还使用了sqlalchemy-migrate(<https://code.google.com/p/sqlalchemy-migrate/>)来处理数据库模式的升级。一切运行良好,直到有一天它们不行了,开始出现大量bug,并且没有好转的迹象。而且,OpenStack在当时是想要支持Python 3的,然而没有任何迹象表明sqlalchemy-migrate要支持Python 3。因此,显然sqlalchemy-migrate已经死了,我们需要切换到其他替代方案。截止到作者写作时,OpenStack正准备升级到Alembic([https://pypi. python.org/pypi/alembic](https://pypi.python.org/pypi/alembic)),虽然也有一些工作要做,但好在不是那么痛苦。
所有这些引出一个重要的问题:“如何保证我不会掉进同样的陷阱里?”很遗憾,没办法保证。程序员也是人,没什么办法可以确保目前维护良好的库在几个月后仍然维护良好。但是,在OpenStack中我们使用下列检查表来根据需要给出建议(我建议你也这么做)。
- Python 3兼容。尽管现在你可能并不准备支持Python 3,但很可能早晚会涉及,所以确认选择的库是Python 3兼容的并且承诺保持兼容是明智的。
- 开发活跃。GitHub(<http://github.com>)和Ohloh(<http://www.ohloh.net/>)通常提供足够的信息来判断一个库是否有维护者仍然在工作。
- 维护活跃。尽管一个库可能是“完成”状态(即功能完备,不会再加入新功能),但应该有维护者仍然在工作,以确保没有bug。可以通过查看项目的跟踪系统来看维护者对bug的反应是否迅速。
- 与各个操作系统发行版打包在一起。如果一个库被打包在主流的Linux发行版内,说明有其他项目依赖它,所以,如果真有什么问题,至少你不是唯一一个抱怨的。如果打算公开发布你的软件,那么这项检查也是很有用的。因为如果软件的依赖已经在终端用户的机器上安装了,显然分发你的软件会更容易。
- API兼容保证。没有比你的软件因为一个它依赖的库发生了变化而使整个API崩溃更糟的了。你一定很想知道选择的库在过去是否发生过类似的事件。
- 许可证。
尽管可能工作量巨大,但这一检查表对于依赖同样适用。如果知道应用程序会大量依赖一个特定的库,那么至少应该对这个库的每一个依赖使用这个检查表。
不管最终使用哪个库,都要像其他工具一样对待,因为即使是有用的工具也可能会造成严重的损害。尽管不常发生,但问问你自己:如果你有一把锤子,你会拿着它满屋跑因而可能意外地损坏屋子里的东西,还是会把它放在工具架上或者车库里,远离那些贵重而易碎的东西,仅在需要的时候才拿出来?
对于外部库道理是一样的,不管它们多么有用,都需要注意避免让这些库和实际的源代码耦合过于紧密。否则,如果出了问题,你就需要切换库,这很可能需要重写大量的代码。更好的办法是写自己的API,用一个包装器对外部库进行封装,将其与自己的源代码隔离。自己的程序无需知道用了什么外部库,只要知道API提供了哪些功能即可。想要换一个不同的库?只需要修改包装器就可以了。只要它仍然提供同样的功能,那么完全不需要修改其余的核心代码。也许会有例外,但应该不会太多。大部分库都被设计成只专注解决一定范围的问题,因此很容易隔离。
5.7.3节将会涉及如何使用入口点构建驱动系统(driver system),这个系统让你可以将项目的某些部分设计成可以根据需要切换的模块。
- 内容提要
- 中文版序
- 前言
- 第1章 项目开始
- 1.1 Python版本
- 1.2 项目布局
- 1.3 版本编号
- 1.4 编码风格与自动检查
- 1.5 Joshua Harlow访谈
- 第2章 模块和库
- 2.1 导入系统
- 2.2 标准库
- 2.3 外部库
- 2.4 框架
- 2.5 Doug Hellmann访谈
- 第3章 管理API变化
- Christophe de Vienne访谈
- 第4章 时区陷阱
- 第5章 文档
- 5.1 Sphinx和reST入门
- 5.2 Sphinx模块
- 5.3 扩展Sphinx
- 第6章 分发
- 6.1 简史
- 6.2 使用pbr打包
- 6.3 Wheel格式
- 6.4 包的安装
- 6.5 和世界分享你的成果
- 6.6 Nick Coghlan访谈
- 6.7 入口点
- 6.7.1 可视化的入口点
- 6.7.2 使用控制台脚本
- 6.7.3 使用插件和驱动程序
- 第7章 虚拟环境
- 第8章 单元测试
- 8.1 基础知识
- 8.2 fixture
- 8.3 模拟(mocking)
- 8.4 场景测试
- 8.5 测试序列与并行
- 8.6 测试覆盖
- 8.7 使用虚拟环境和tox
- 8.8 测试策略
- 8.9 Robert Collins访谈
- 第9章 方法和装饰器
- 9.1 创建装饰器
- 9.2 Python中方法的运行机制
- 9.3 静态方法
- 9.4 类方法
- 9.5 抽象方法
- 9.6 混合使用静态方法、类方法和抽象方法
- 9.7 关于super的真相
- 第10章 函数式编程
- 10.1 生成器
- 10.2 列表推导
- 10.3 函数式函数的函数化
- 第11章 抽象语法树
- 11.1 用抽象语法树检查来扩展flake8
- 11.2 Hy
- 11.3 Paul Tagliamonte访谈
- 第12章 性能与优化
- 12.1 数据结构
- 12.2 性能分析
- 12.3 有序列表和二分查找
- 12.4 namedtuple和slots
- 12.5 memoization
- 12.6 PyPy
- 12.7 通过缓冲区协议实现零复制
- 12.8 Victor Stinner访谈
- 第13章 扩展与架构
- 13.1 多线程的注意事项
- 13.2 多进程与多线程
- 13.3 异步和事件驱动架构
- 13.4 面向服务架构
- 第14章 RDBMS和ORM
- 14.1 用Flask和PostgreSQL流化数据
- 14.2 Dimitri Fontaine访谈
- 第15章 Python 3支持策略
- 15.1 语言和标准库
- 15.2 外部库
- 15.3 使用six
- 第16章 少即是多
- 16.1 单分发器
- 16.2 上下文管理器
- 第17章 延伸阅读
- 版权信息
- 版权声明
- 欢迎来到异步社区!
- 异步社区的来历
- 社区里都有什么?
- 购买图书
- 下载资源
- 与作译者互动
- 灵活优惠的购书
- 纸电图书组合购买
- 社区里还可以做什么?
- 提交勘误
- 写作
- 会议活动早知道
- 加入异步