← 返回题目列表

Python 项目如何做依赖管理和可重复构建?

高频 中等 第 12 / 27 题 更新于 2026/07/27
依赖管理requirementsPoetrypip-tools可重复构建

简化版

Python 依赖管理要区分直接依赖和锁定依赖,保证不同环境安装到一致版本。常见方案有 requirements.txt、pip-tools、Poetry、uv 等;工程上要固定 Python 版本、提交锁文件、隔离虚拟环境,并在 CI 中验证可重复安装。

详细版

依赖管理关注几个问题:

  • 项目需要哪些直接依赖;
  • 间接依赖版本如何锁定;
  • 开发、测试、生产依赖如何区分;
  • Python 版本如何约束;
  • 构建环境是否可重复;
  • 依赖是否存在安全漏洞。

常见方式:

  • 简单项目:requirements.txt
  • 更可控:pip-tools 的 requirements.in + requirements.txt
  • 包管理和发布:Poetry 或现代 pyproject.toml
  • 追求速度和锁定体验:uv。

面试重点是:只写一个不带版本的 requirements,很难保证可重复构建。

完整版教学

一、为什么 Python 依赖管理容易出问题

Python 生态非常灵活,但灵活也带来环境不一致问题。开发者本地安装的是某个版本,CI 安装的是另一个版本,生产镜像又因为缓存拿到第三个版本,问题就会很隐蔽。

例如你写:

fastapi
sqlalchemy

这没有锁定版本。今天安装可能是一个版本,几个月后重新安装可能得到新版本。新版本可能改了行为,项目就可能突然失败。

所以依赖管理的核心目标是可重复:同一份代码在不同机器、不同时间安装,应尽量得到一致依赖。

二、直接依赖和间接依赖

直接依赖是你项目明确使用的库,例如 FastAPI、SQLAlchemy、pytest。间接依赖是这些库依赖的库,例如 Starlette、Pydantic、anyio。

只管理直接依赖是不够的,因为间接依赖变化也可能影响项目。锁文件的价值就在于记录完整依赖树。

比如 pip-tools 的做法是:requirements.in 写直接依赖,生成的 requirements.txt 锁定完整版本。

# requirements.in
fastapi
sqlalchemy

生成后可能得到:

fastapi==0.x.x
pydantic==x.x.x
starlette==x.x.x
sqlalchemy==x.x.x

生产安装使用锁定后的文件。

三、requirements.txt、pip-tools、Poetry 怎么选

requirements.txt 简单直接,适合小项目。但如果手动维护完整依赖树,容易混乱。

pip-tools 比较适合想保留 pip 工作流,又希望锁定依赖的团队。它用 pip-compile 生成锁定文件,用 pip-sync 同步环境。

Poetry 提供项目元数据、依赖解析、虚拟环境、构建发布和 lock 文件,适合库项目或较规范的应用项目。

uv 是较新的工具,速度快,支持依赖解析、锁定和虚拟环境管理,越来越多团队在尝试。

面试回答不要只背工具名,要说清楚目标:固定依赖树、隔离环境、保证 CI 和生产可重复。

四、pyproject.toml 的意义

现代 Python 项目越来越多使用 pyproject.toml。它可以集中描述项目元数据、构建系统、依赖、工具配置。例如 black、ruff、mypy、pytest 都可以在里面放配置。

这比散落多个配置文件更统一。对于可发布包,pyproject.toml 也是标准化构建入口。

工程中常见结构:

pyproject.toml
poetry.lock / uv.lock
src/
tests/

这类结构让项目更容易被 CI、构建工具和 IDE 识别。

五、虚拟环境和 Python 版本

依赖管理还必须包含 Python 版本管理。某些库只支持 Python 3.10+,某些语法只在 Python 3.11 可用。如果不约束版本,本地和生产可能出现语法或依赖兼容问题。

可以在 pyproject.toml 中声明:

requires-python = ">=3.11,<3.13"

虚拟环境用于隔离项目依赖,避免全局 Python 被污染。无论用 venv、Poetry 还是 uv,本质都是给项目一个独立环境。

六、生产构建要注意什么

生产镜像应该使用锁定依赖安装,不要每次解析最新版本。构建过程中要尽量可缓存、可复现。

还要区分开发依赖和生产依赖。pytest、black、mypy 这类工具通常不需要进入生产运行环境。生产镜像越小,攻击面和构建时间越可控。

依赖安全扫描也很重要。可以在 CI 中使用 pip-audit、Safety 或平台安全扫描检查已知漏洞。

七、常见误区与追问

文件或配置记录内容工程意义
requirements.in直接依赖人维护项目真正需要的库
requirements.txt完整锁定依赖树CI/生产按固定版本安装
pyproject.toml项目元数据和工具配置统一构建、依赖、测试工具入口
lock 文件解析后的版本图保证不同机器重复安装
只写 fastapi:
今天可能解析到 fastapi A + pydantic X
3 个月后可能解析到 fastapi B + pydantic Y
如果没有锁文件,同一份代码构建结果可能不同。

易错点:直接依赖回答“项目想要什么”,锁文件回答“最终实际装什么”。

第一个误区是不提交锁文件。团队成员和 CI 解析出的版本可能不同。

第二个误区是依赖版本完全不限制。上游库升级可能带来破坏性变化。

第三个误区是把开发依赖装进生产镜像。镜像变大,也增加安全风险。

第四个误区是只在本地验证安装。真正要在 CI 中从零安装一次,才能证明依赖声明完整。

  • 误区:requirements.txt 里不写版本也算依赖管理。 不锁版本会让安装结果随时间变化,可重复构建无法保证。
  • 误区:只锁直接依赖就够了。 间接依赖也可能破坏项目,锁文件要记录完整依赖树。
  • 误区:开发依赖可以直接进生产镜像。 pytest、black、mypy 等工具会增加镜像体积和攻击面,生产依赖应尽量精简。
  • 追问:pip-tools 和 Poetry 的差别怎么答? pip-tools 保留 pip 工作流,用输入文件生成锁定 requirements;Poetry 更偏项目管理,包含依赖解析、虚拟环境、构建发布和 lock。
  • 追问:为什么 CI 要从零安装依赖? 只有干净环境安装成功,才能证明依赖声明完整,不依赖开发者本地缓存或隐藏包。
  • 追问:Python 版本为什么也要锁定范围? 语法、标准库行为、二进制包兼容性都和 Python 版本有关,只锁依赖不锁解释器仍可能不可重复。

八、加强记忆

记 Python 依赖管理:直接依赖说明“我需要什么”,锁文件说明“实际安装什么”。工程上要固定 Python 版本、隔离虚拟环境、提交锁文件、区分开发和生产依赖,并在 CI 中验证可重复构建。