对于较大型软件的开发,通常会有成千上万的 Python 模块,如果把所有模块都存储在同一个 Python 文件之内,显然是不现实的,因为那样会使代码变得臃肿且难以维护。

一个更好的办法是,按照功能不同,将多个模块分门别类存储在不同文件中,进而实现“物以类聚,‘码’以群分”,将功能自成体系、模块彼此支撑的多个 Python 文件打包在一起,将不同功能块分别存储于不同 Python 文件夹中。

于是,就出现了 Python 的“包”(package)的概念。简单来看,一个包就是包含若干模块的文件夹。显然,包是比模块更大的概念(一个模块可简单理解为单个 .py 文件),它可视为若干相关模块的集合。

包是 Python 用来组织命名空间(namespace)和类的重要媒介。为了让 Python 能感知到这些模块,只需要让 Python 感知这个文件夹所在的位置即可,相比于模块的告知方式,Python 的包管理更加简单。

创建一个包主要包括如下三步:

创建一个文件夹(文件夹的名字最好能做到见名知意),文件夹的名称即包的名称;

在文件夹中创建一个__init__.py 文件。通常 __init__.py 文件的内容为空,其存在的意义就是要告知 Python 解释器,当前文件夹被标记为一个包;

将相关的模块放置于该文件夹内。

这样一来,一个 Python 包就创建好了。

假设我们有如下的文件分布结构,通过前面的讨论可知,这个包的名称叫 package,它里面包括三个模块,分别为 parameters、urllib 和 test。

|——package

| | ——__init__.py

| | ——parameters.py

| | ——urllib .py

| | ——test.py

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

In [7]: import package.parameters as pm #模块名太长,可以取一个别名 pm

In [8]: pm.PI #输出导入模块中的参数

Out[8]: 3.1415926

需要注意的是,如果想访问包内的模块,正确的格式是“包名.模块名”,如 pm.PI。

当然,我们还可以在 __init__.py 文件中做点文章,增加其他功能。我们在导入一个包时,实际上是导入了它的 __init__.py 文件(有点像 C、C++ 的头文件)。我们可以在 __init__.py 文件中事先批量导入我们所需要的模块,而不再逐个导入。

比如说,__init__.py 的源代码如下。

#我所在的文件夹名为 package

#我是 _init_.py

import parameters

import urllib

import test

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

#我是另外一个文件 other.py

import package

print(package.parameters, package.urllib, package.test)

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

In [9]: %run other.py

从输出可以看出,parameters、urllib 和 test 这三个模块被批量导入了。

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

#我所在的文件夹名为 package

#我是__init__.py

__all__ = ['parameters', 'urllib', 'test'] #定义导入的模块名称

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

#我是另外一个文件other.py

from package import * #导入包 package 中的所有模块

print(parameters, urllib, test) #输出所有模块的名称

print (parameters.PI) #输出模块 parameters 中的参数PI

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

In [10]: %run other.py

3.1415926

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