浅谈大型项目的模块化开发(Based on Python)

1789 字
9 分钟
浅谈大型项目的模块化开发(Based on Python)

写在前面#

最近在进行大型项目开发时,自行实现的一些公共模块,包括工具库、API 客户端等,都被扔在一个文件夹下,需要时由该项目的控制代码进行调用,不过因为水平之菜,经过测试没什么问题的代码 PR 上去之后经常会出现需要反复修改的情况。而且另一方面,这些公共模块具有一定的可移植性,但只被一个项目使用,没什么性价比,肯定是需要进一步考虑能够在多个项目实现复用的。

一种好的管理方式(至少是大部分大型开源项目都在使用的方式)是将公共模块单独管理,模块可以独立更新,不必和主项目的提交历史绑在一起,也利好多人协作开发。具体方法包括 Git 的 Submodule 和打包为 Python Package 进行导入两种。

一、Git Submodule#

1.1 简介#

Git submodule 是 git 原生引用和管理第三方资源的方法。

假如你的项目结构如下:

Main Project
└── src/
└── module/
└── module_1/

如果用 Git submodule 实现对 module_1 的管理,那么主项目 Git 仓库显然作为父仓库 (Superproject),而 module_1 就作为子模块 (Submodule),父仓库只记录子模块的 Git 仓库地址 和当前的 提交哈希,不会直接存储子模块的代码历史。

1.2 操作步骤#

食用方法也很简单,子模块和父模块都先建立一个单独的 Git 仓库,git add/commit/push 这些我就不细说了,现在假设两者的仓库都已经建立了,接下来就是 git submodule 的操作了:

  1. 在父仓库中添加子模块:
Terminal window
git submodule add <子模块的仓库地址> <子模块在父模块中的相对路径>

e.g.

Terminal window
git submodule add https://github.com/user/module_1.git module/module_1
# 等价于
git submodule add https://github.com/user/module_1.git module/

那么父仓库具体是如何记录这一信息的呢?在执行上述操作后,可以看到在父仓库根目录会生成一个 .gitmodules 文件,内容形如:

[submodule "module/module_1"]
path = module/module_1
url = https://github.com/user/module_1.git

也可以通过以下命令查看子模块信息:

Terminal window
git submodule status
git submodule foreach "git status"
  1. 初始化子模块:当协作者或其他用户克隆你的父仓库,即主项目时,默认子模块的目录是空的,需要手动拉取子模块代码:
Terminal window
git submodule init
git submodule update

当然,Git 也提供了在克隆时就一步到位的选项:

Terminal window
git clone --recurse-submodules <父仓库地址>
  1. 更新子模块:当子模块仓库有新提交时,你可以进入子模块目录拉取最新代码(当然,回退版本也同理):
Terminal window
cd module/module_1
git pull origin main
# 如果是回退,则执行
git checkout <子模块需要回退到的某个commit或分支>

我们前面提到过,两者的提交历史是独立的,父仓库只记录子模块的当前提交哈希,子模块仓库的更新并不会同步到父仓库中,所以父仓库还需要手动提交:

Terminal window
cd ../..
git add module/module_1
git commit -m "Update submodule module_1 to latest version"

这时候,父仓库记录的才是子模块的最新提交哈希。

  1. 删除子模块:删除步骤稍复杂,需要手动清理:
Terminal window
git submodule deinit -f module/module_1
git rm -f module/module_1
rm -rf .git/modules/module/module_1

1.3 好处#

Git Submodule 将公共库抽离成单独 Git 仓库,父项目通过 Submodule 管理这些模块,保持版本可控。如需自动拉取子模块代码,也可以在 Github Action 等 CI/CD 工具中执行:

Terminal window
git submodule update --init --recursive

从而自动进行构建。

二、Python Package#

2.1 简介#

Python Package 也是一种常见方式,经常会用到的 Numpy 等就是 Package。这些第三方库能直接通过 pip 安装,分发、复用于各种项目中,虽然你用起来大道至简,但是这是 Package 的维护者在背后为你负重前行,也就是“打包”的过程,具体的打包过程可以从内到外分为三层,下图源自 Python Packaging 的官方文档,非常直观:

  1. .py 独立模块(Standalone Modules):可以直接导入,但无法通过 pip install 方式分发;
  2. sdist 源码分发包(Source Distribution Package):通过 setup.py、pyproject.toml 等安装元数据,打包成压缩文件(.tar.gz、.zip);
  3. wheel 预编译包(Built Distribution Package):属于 binary package(二进制分发),简单来说就是预编译好的轮子,可以直接安装,例如 pip install my_package.whl ;

2.2 操作步骤#

以下以一个简单的例子为例,简单过一下打包步骤:

假如原始的代码结构如下:

my_package/
└── src/
└── module_a/
├── __init__.py
    └── module_a.py
└── module_b/
├── __init__.py
        └── module_b.py
  1. 准备项目信息:如果 Package 想要发布,还需要添加一些基本的信息,一般通过 setup.py 或 pyproject.toml ;
my_project/
├── LICENSE # 授权
├── setup.py # 安装设定
├── pyproject.toml # 安装设定
├── README.md
├── src/ # 包源码
└── my_package/
├── __init__.py
└── ...
└── test/ # 测试程序
  1. 编写元数据:一个基本的 setup.py 和 pyproject.toml 示例如下:
from setuptools import setup, find_packages
setup(
name="my_package",
version="0.1.0",
description="A useful Python package",
author="Your Name",
author_email="you@example.com",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
"numpy>=1.19.0",
"requests"
],
python_requires='>=3.7',
)
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
version = "0.1.0"
authors = [
{ name="Your Name", email="you@example.com" },
]
description = "A useful Python package"
readme = "README.md"
requires-python = ">=3.7"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]

基本要素是类似的,也可以混用,现代打包一般采用后者,当然也有很多其他工具,这两种属于是最主流的了。

  1. 构建包:这一步是可选的,但是一般如果想要发布都会进行 build,提供更快速的安装;
Terminal window
python -m build

2.3 发布到 PyPI#

PyPI,即 Python Package Index,是 Python 官方的第三方软件存储库,账号注册就不赘述了,下面简单讲一下上传步骤:

pip install twine
twine upload dist/*

上传成功后,别人就可以直接使用 pip install my_package 来安装你发布的 Package 了。

很多 Package 一般都自动构建并上传,你可以随便找一个开源项目并在里面看到:

.github/
└── workflows/
└── publish.yml

完全可以学学它们的 publish.yml 以及项目结构,这里给出一个简单的示例:

name: Publish Python Package
on:
push:
tags:
- 'v*' # 当你创建 v1.0.0 这种 tag 时自动触发
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build package
run: python -m build
- name: Publish to PyPI
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
twine upload dist/*

Token 需要你自行在 PyPI 中获取并在 Github 中的项目仓库 →\rightarrow Settings →\rightarrow Secrets and variables →\rightarrow Actions →\rightarrow 点击 New repository secret ,创建 PYPI_USERNAME 和 PYPI_PASSWORD,注意千万不要显式写在工作流中!

完成后,当提交代码并推送 Tag 时:

Terminal window
git tag v1.0.0
git push origin v1.0.0

GitHub Actions 会自动运行 workflow,构建 wheel 和 sdist 包,并上传到 PyPI。

也可以替换为:

on:
release:
types: [published]

这样就是在发布 Release 后自动触发。

参考资料#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

浅谈大型项目的模块化开发(Based on Python)
https://blog.yokumi.cn/posts/modular-development-for-large-scale-projects-based-on-python/
作者
Yokumi
发布于
2025-08-05
许可协议
CC BY-NC-SA 4.0
相关文章智能推荐
1
Python 套件管理器 uv 使用介绍
开发心得Python 生态得益于大数据时代和大模型时代蓬勃发展,相应的包管理工具也不断涌现,这篇文章简单记录一下个人上手 Astral 团队开发的 uv 的一些基操和使用一段时间后的体验。当然其实官方文档[^1]已经很详细了。 下表转载自 Shoukai Huang 大佬的博客[^2] 整理的横向对比:
2
NSFC 数据爬取
开发心得从国家自然科学基金大数据知识管理服务门户爬取论文数据。 在网页的 JavaScript 文件中,尝试寻找相关的解密代码,最终在app.17b88e26.js中找到以下内容(注释为后期补充): 使用 Python 的 pycryptodome 库来实现解密:
3
第一台 VPS 折腾小记
开发心得在使用本项目/教程/脚本之前,请务必仔细阅读以下声明。一旦您开始使用、复制或修改相关内容,即视为您已完全接受并同意本免责声明的所有条款。 请谨记:使用技术时请务必遵守您所在国家和地区的法律法规。 使用 IPv6-only VPS 低成本独享家宽,解锁 ChatGPT 不风控
4
2026.5 Live Repo
生活杂谈翻了翻相册才发现上一次已经是去年 9 月的羊文学了,哎gszm坏事做尽。 这回的出行方式是经典京沪高铁二等座,去年锅贴得意之作绿皮 D9 真给我坐麻了,这次果断 G 系列。不过被课表背刺,本来还可以买早一班(),结果就是快 0 点才到虹桥。好像是第一次这么晚到沪国。
5
在 Linux 下编译安装 Dynamips 和 Dynagen 搭建 Cisco 实验环境
开发心得最终还是花了一点时间把计网实践的实验平台搞到 Linux 下实现了,相比于 Windows,同样配置的路由器,Linux 下 CPU 占用可降低 50% 以上,应该也会更加稳定吧。 本文将详细介绍如何在 Linux (Ubuntu/Debian) 系统下(macOS 等也是类似的,一些依赖的安装略有不同罢了)从源码编…

评论区

文章目录