本篇我们介绍 Python 中的包(package),学习如何使用包构建应用程序。
Python 包
假如我们需要开发一个大型应用,用于处理从下单到支付的销售流程。这个应用将会包含许多模块,随着模块数量的增加,很难在一个地方维护所有的模块。与此同时,我们也想要将模块按照一定的方式进行分组。此时,我们就需要使用包。
包可以按照层次结构组织模块。Python 包和模块的结构就像操作系统中的文件夹和文件。创建包就是创建一个文件夹,然后将相关的模块文件存储到该文件夹。
为了让 Python 将一个文件夹当作包使用,我们需要在文件夹中创建一个 __init__.py 文件。
注意,从 Python 3.3 开始引入了隐式命名空间包的功能,允许 Python 将一个没有 __init__.py 文件的文件夹当作包使用。
例如,下图显式了 sales 包的文件结构,包含了 order、delivery 以及 billing 三个包:
导入包
使用 import 语句导入包的语法如下:
import package.module
然后,访问模块中对象的语法如下:
package.module.function
以下示例使用了 sales 包中 order、delivery 以及 billing 模块函数:
# main.py
import sales.order
import sales.delivery
import sales.billing
sales.order.create_sales_order()
sales.delivery.create_delivery()
sales.billing.create_billing()
为了简化代码,我们可以使用以下语句导入模块中的函数:
from module import function
例如:
# main.py
from sales.order import create_sales_order
from sales.delivery import create_delivery
from sales.billing import create_billing
create_sales_order()
create_delivery()
create_billing()
也可以在导入对象时进行重命名操作:
# main.py
from sales.order import create_sales_order as create_order
from sales.delivery import create_delivery as start_delivery
from sales.billing import create_billing as issue_billing
create_order()
start_delivery()
issue_billing()
包的初始化
按照惯例,当我们导入一个包时,Python 会执行包中的 __init__.py 文件。因此,我们可以在 __init__.py 文件文件中初始化包级别的数据。
以下示例在 sales 包的 __init__.py 文件中定义了一个默认的税率:
# __init__.py
# default sales tax rate
TAX_RATE = 0.07
在 main.py 文件中,我们可以访问 sales 包中的 TAX_RATE:
# main.py
from sales import TAX_RATE
print(TAX_RATE)
除了初始化数据之外,__init__.py 文件也可以用于导入其他包中的模块。例如:
# __init__.py
# import the order module automatically
from sales.order import create_sales_order
# default sales tax rate
TAX_RATE = 0.07
在 main.py 文件导入 sales 包之后,可以直接使用 create_sales_order 函数:
# main.py
import sales
sales.order.create_sales_order()
from package import *
当我们使用以下语句导入包中的全部对象:
from package import *
Python 会查找 __init__.py 文件。如果该文件存在,Python 将加载文件中一个特殊的列表 __all__ 中包含的所有模块。例如,我们可以在 __all__ 列表中添加以下模块:
# __init__.py
__all__ = [
'order',
'delivery'
]
然后在 main.py 文件中使用以下导入语句:
# main.py
from sales import *
order.create_sales_order()
delivery.create_delivery()
# cannot access the billing module
我们在 main.py 文件中访问了 order 和 delivery 模块中的函数。不过,我们无法使用 billing 模块,因为它不在 __all__ 列表中。
子包
Python 包可以包含子包。子包可以用于进一步组织模块。
下图中的 sales 包包含了三个子包:order、delivery 以及 billing。每个子包都有相应的模块。我们可以将其他与订单处理相关的模块放入 order 子包:
包相关的操作也可以用于子包。例如,我们可以使用以下语句导入 order 子包中的函数:
# main.py
from sales.order import create_sales_order
create_sales_order()
总结
- 一个 Python 包包含一个或多个模块。Python 使用文件夹和文件结构管理包和模块。
- __init__.py 文件用于初始化包级别的数据。
- __all__ 变量中的模块会在导入包时自动加载。
- 包可以包含子包。