(九)用包组织多个模块
现在把可复用函数与项目启动入口放在同一组目录中。下面的结构保存在 package_demo 文件夹:
package_demo/
└── readingkit/
├── __init__.py
├── core.py
└── __main__.py
readingkit 是包名。本例用 __init__.py 明确建立普通包;它会在包首次导入时执行,可以只保存说明文字。Python 也支持没有这个文件的命名空间包,这里先用能看清入口的普通包组织项目。
# 项目文件:package_demo/readingkit/__init__.py
# 包的初始化文件只保存说明,不在导入时启动统计程序。
"""阅读统计工具。"""# 项目文件:package_demo/readingkit/core.py
# 计算模块只接收数据并返回结果,供不同入口复用。
def total_minutes(values):
return sum(values)# 项目文件:package_demo/readingkit/__main__.py
# 开头的点表示从当前包 readingkit 中导入 core 模块的函数。
from .core import total_minutes
def main():
print(total_minutes([20, 35]))
if __name__ == "__main__":
main()在 package_demo 目录运行:
# -m 后面写包名,Python 找到并执行包里的 __main__.py。
python -m readingkit
输出 55。先找到 readingkit,执行包的初始化文件,再执行 readingkit/__main__.py。入口里的 .core 是相对导入;写成 from readingkit.core import total_minutes 则是绝对导入。
直接运行 python readingkit/__main__.py,解释器把它当作独立脚本,.core 缺少所属包的信息,会出现相对导入错误。对这套结构,在包的上一级用 python -m readingkit 启动,包名与相对导入就能对应起来。
这里的文件夹是项目源码。第一章中 pip 安装的第三方分发包,也会向环境中提供可导入的模块或包;安装名称和导入名称仍可能不同。项目的构建、可编辑安装和跨目录运行会在项目组织章节中继续完成。