
3.4 创建模块包
对于较大型软件的开发,通常会有成千上万的Python模块,如果把所有模块都存储在同一个Python文件之内,显然是不现实的,因为那样会使代码变得臃肿且难以维护。
一个更好的办法是,按照功能不同,将多个模块分门别类存储在不同文件中,进而实现“物以类聚,‘码’以群分”,将功能自成体系、模块彼此支撑的多个Python文件打包在一起,将不同功能块分别存储于不同Python文件夹中。
于是,就出现了Python的“包”(package)的概念。简单来看,一个包就是包含若干模块的文件夹。显然,包是比模块更大的概念(一个模块可简单理解为单个.py文件),它可视为若干相关模块的集合。
包是Python用来组织命名空间(namespace)和类的重要媒介。为了让Python能感知到这些模块,只需要让Python感知这个文件夹所在的位置即可,相比于模块的告知方式,Python的包管理更加简单。
创建一个包主要包括如下三步。
1.创建一个文件夹(文件夹的名字最好能做到见名知意),文件夹的名称即包的名称。
2.在文件夹中创建一个__init__.py文件。通常__init__.py文件的内容为空,其存在的意义就是要告知Python解释器,当前文件夹被标记为一个包。
3.将相关的模块放置于该文件夹内。
这样一来,一个Python包就创建好了。
假设我们有如下的文件分布结构,通过前面的讨论可知,这个包的名称叫package,它里面包括三个模块,分别为parameters、urllib和test(参见随书源代码)。

假设我们想使用包package下的模块parameters,则可以如下操作。

需要注意的是,如果想访问包内的模块,正确的格式是“包名.模块名”,如pm.PI。
当然,我们还可以在__init__.py文件中做点文章,增加其他功能。我们在导入一个包时,实际上是导入了它的__init__.py文件(有点像C、C++的头文件)。我们可以在__init__.py文件中事先批量导入我们所需要的模块,而不再逐个导入。
比如说,__init__.py的源代码如下。

然后我们在另外一个文件中导入这个包,如下所示。

然后我们在IPython的命令行执行这个程序,输出结果如下。

从输出可以看出,parameters、urllib和test这三个模块被批量导入了。
实际上,__init__.py中还有一个重要的变量__all__,其作用是,由它定义的对象可在执行“from包名import *”命令时,自动把__all__定义的模块,一次性批量导入。__init__.py中的代码如下。

然后在另外一个文件(改写前面的other.py)中导入这个包中的所有模块,如下所示。

上面第02行代码会把注册在__init__.py文件中的__all__列表中的模块,都导入当前文件(即other.py)中。然后,我们在IPython命令行执行这个程序,输出结果如下。

从上面的输出结果可以看出,一切正如我们预期的那样。