- 译者序
- 前言
- 第1章 问答环节
- 第2章 Python 如何运行程序
- 第3章 如何运行程序
- 第4章 介绍 Python 对象类型
- 第5章 数字
- 第6章 动态类型简介
- 第7章 字符串
- 第8章 列表与字典
- 第9章 元组、文件及其他
- 第10章 Python 语句简介
- 第11章 赋值、表达式和打印
- 第12章 if 测试和语法规则
- 第13章 while 和 for 循环
- 第14章 迭代器和解析,第一部分
- 第15章 文档
- 第16章 函数基础
- 第17章 作用域
- 第18章 参数
- 第19章 函数的高级话题
- 第20章 迭代和解析,第二部分
- 第21章 模块:宏伟蓝图
- 第22章 模块代码编写基础
- 第23章 模块包
- 第24章 高级模块话题
- 第25章 OOP:宏伟蓝图
- 第27章 更多实例
- 第28章 类代码编写细节
- 第29章 运算符重载
- 第30章 类的设计
- 第31章 类的高级主题
- 第32章 异常基础
- 第34章 异常对象
- 第35章 异常的设计
- 第36章 Unicode 和字节字符串
- 字符串基础知识
- Python 的字符串类型
- 文本和二进制文件
- Python 3.0 中的字符串应用
- 转换
- 编码 Unicode 字符串
- 编码非ASCII文本
- 编码和解码非ASCII文本
- 其他 Unicode 编码技术
- 转换编码
- 在 Python 2.6 中编码 Unicode 字符串
- 源文件字符集编码声明
- 使用 Python 3.0 Bytes 对象
- 序列操作
- 创建 bytes 对象的其他方式
- 混合字符串类型
- 使用 Python 3.0(和 Python 2.6)bytearray 对象
- 使用文本文件和二进制文件
- Python 3.0 中的文本和二进制模式
- 类型和内容错误匹配
- 使用 Unicode 文件
- 在 Python 3.0 中处理 BOM
- Python 2.6 中的 Unicode 文件
- Python 3.0 中其他字符串工具的变化
- Struct二进制数据模块
- pickle对象序列化模块
- XML解析工具
- 本章小结
- 本章习题
- 习题解答
- 第37章 管理属性
- 第38章 装饰器
- 第39章 元类
- 附录A 安装和配置
- 附录B 各部分练习题的解答
- 作者介绍
- 封面介绍
为什么要使用包导入
首先,因为包导入提供了程序文件的目录信息,因此可以轻松地找到文件,从而可以作为组织工具来使用。没有包导入时,通常得通过查看模块搜索路径才能找出文件。再者,如果根据功能把文件组织成子目录,包导入会让模块扮演的角色更为明显,也使代码更具可读性。例如,正常导入模块搜索路径上某个目录内的文件时,就像这样:
与下面包含路径的导入相比,提供的信息就更少:
包导入也可以大幅简化PYTHONPATH和.pth文件搜索路径设置。实际上,如果所有跨目录的导入,都使用包导入,并且让这些包导入都相对于一个共同的根目录,把所有Python程序代码都存在其中,在搜索路径上就只需一个单独的接入点:通用的根目录。最后,包导入让你想导入的文件更明确,从而解决了模糊性。下一节要深入探索包导入所扮演的角色。
三个系统的传说
实际中需要包导入的场合,就是解决当多个同名程序文件安装在同一个机器上时,所引发的模糊性。这是与安装相关的问题,也是通常实际中所要留意的地方。让我们用一个假设的场景来说明。
假设程序员开发了一个Python程序,它包含了一个文件utilities.py,其中包含了通用的工具代码,还有一个顶层文件main.py让用户来启动程序。这个程序的文件会以import utilities加载并使用通用的代码。当程序分发给用户时,采用的是.tar或.zip文件的形式,其中包含了该程序的所有文件,而当它在安装时,会把所有文件解压放进目标机器上的某一个名为system1的目录中。
现在,假设有第二位程序员开发了另一个不同的程序,而其文件也命名为utilities.py和main.py,而且同样也在程序文件中使用import utilities来加载一般的代码文件。当获得第二个系统并安装在和第一个系统相同的计算机上时,它的文件会解压并安装至接收机器上某处文件夹名为system2的新目录内,使其不会覆写第一个系统的同名文件。
到目前为止,都没有什么问题:两个系统可共存,在同一台机器上运行。而实际上,不需要配置模块搜索路径,来使用计算机上的这些程序。因为Python总是先搜索主目录(也就是包含顶层文件的目录),任一个系统内的文件的导入,都会自动看见该系统目录内的所有文件。例如,如果点击system1\main.py,所有的导入都会先搜索system1。同样地,如果启动system2\main.py,则会改为先搜索system2。记住,只有在跨目录进行导入时才需要模块搜索路径的设置。
尽管如此,假设在机器上安装这两套程序之后,决定在自己的系统中使用每一个utilities.py文件内的一些程序代码。毕竟,这是通用工具的代码,而Python代码的本质都是想再利用的。就此而言,想在第三个目录内所编写的文件内写下了下面的代码,来载入两个文件其中的一个:
现在,问题开始出现了。为了让这能够工作,需要设置模块搜索路径,引入包含utilities.py文件的目录。但是,要在路径内先放哪个目录呢:system1还是system2?
这个问题在于搜索路径本质上是线性的。搜索总是从左至右扫描,所以不管这个困境你想多久,一定会得到搜索路径上最左侧(最先列出)的目录内的utilities.py。也就是说,永远无法导入另一个目录的那个文件。每次导入操作时,可以试着在脚本内修改sys.path,但那是外部的工作,很容易出错。在默认情况下,可以说你走到了一个死胡同。这个问题正是包所能够解决的。不要在单独的目录内把文件安装成单纯的文件列表,而是将它们打包,在共同根目录之下,安装成子目录。例如,可能想组织这个例子中的所有代码,变成下面这样的安装层次。
现在,就是把共同根目录添加到搜索路径中。如果程序代码的导入就相对于这个通用的根目录,就能以包导入,导入任何一个系统的工具文件:该文件所在目录名称会使其路径具有唯一性(因此,引用的模块也是这样)。事实上,只要使用import语句,就可以在同一个模块内导入这两个工具文件,而每次引用工具模块时,都要重复其完整的路径。
在这里,所在目录名称让模块的引用变得具有唯一性。
注意:如果需要读取两个或两个以上路径内的同名属性时,才需要使用import,在这种情况下不能用from。如果被调用的函数名称在每个路径内都不同,from语句就可以避免每当调用其中一个函数时,就得重复完整的包的路径的问题,这一点先前已经说过。
此外,注意到,在前边所展示的安装层次中,__init__.py文件已加入到system1和system2目录中来使其工作,但是不需要在根目录内增加。只有在程序代码内,import语句所列的目录才需要这些文件。回想一下,Python首次通过包的目录处理导入时,这些文件就会自动运行了。
从技术上来讲,在这种情况下,system3目录不需要放在根目录下:只有被导入的代码包需要。然而,因为不知道何时模块可能在其他程序中有用,你可能还是想将其放在通用的根目录下,来避免以后类似的变量名冲突问题。
最后,注意两个初始系统的导入依然正常运作。因为它们的主目录都会先搜索,在搜索路径上多余的通用根目录,对于system1和system2内的代码是不相关的。它们只需写import utilities,就可以找到自己的文件。再者,如果在通用的根目录下解开所有的Python系统,路径配置就会变得很简单:只需要一次添加通用的根目录就可以了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论