requirements.txt 不再被推荐作为生产依赖管理方式,因其仅为扁平化导出产物,缺乏来源追踪、环境区分、条件依赖支持及可重现锁机制;应改用 pyproject.toml 声明依赖并配合锁文件(如 poetry.lock)。

requirements.txt 为什么不再被推荐作为生产依赖管理方式
Python 官方(PEP 621、pip 23.1+)和主流工具链(poetry、pip-tools、uv)已明确将 requirements.txt 视为“扁平化导出产物”,而非源声明。它不记录依赖来源(是直接安装的?还是子依赖?)、不区分开发/生产环境、无法表达条件依赖(如 platform_system == "Windows"),更不支持可重现的锁机制——你看到的 requests==2.31.0 可能来自不同版本的 setuptools 解析,导致本地与 CI 行为不一致。
-
requirements.txt是“快照”,不是“合约” - 它没有元数据字段(比如作者、分类器、Python 版本约束)
- 所有依赖都被压平,丢失层级关系,
pip install -r requirements.txt实际执行的是无上下文的线性安装
替代方案:pyproject.toml + 依赖锁文件(如 requirements.lock 或 poetry.lock)
现在标准做法是用 pyproject.toml 声明项目元信息和直接依赖,再由工具生成带哈希、平台、Python 版本标记的锁文件。这解决了 requirements.txt 的核心缺陷:不可重现、不可追溯、不可分组。
- 使用
pip-tools:写pyproject.toml或requirements.in,运行pip-compile --resolver=backtracking生成带哈希的requirements.txt(注意:这只是兼容层,实际应叫requirements.lock) - 使用
poetry:pyproject.toml中写[tool.poetry.dependencies],运行poetry lock生成poetry.lock - 使用
uv:uv pip compile pyproject.toml -o requirements.lock,速度更快,解析更严格
迁移时最容易踩的三个坑
很多团队在“把旧 requirements.txt 搬进 pyproject.toml”时掉进细节陷阱:
- 直接复制粘贴版本号到
[project.dependencies],却没处理-e .或git+https://...这类 VCS 依赖——它们必须改写成 PEP 508 格式,例如:"mylib @ git+<a href="https://www.php.cn/link/60d179bc263ce0fe8e342c2ea1e67fe6">https://www.php.cn/link/60d179bc263ce0fe8e342c2ea1e67fe6</a>" - 忽略
python字段约束:[project.requires-python] = ">=3.9"缺失会导致不同环境中解析出不同依赖树 - 把
dev-requirements.txt简单合并进主依赖——应该用[project.optional-dependencies](如dev = ["pytest", "black"]),再通过pip install ".[dev]"安装
CI/CD 和容器镜像里怎么安全用新流程
Dockerfile 或 GitHub Actions 里继续写 pip install -r requirements.txt 是倒退。正确路径是:
立即学习“Python免费学习笔记(深入)”;
- 构建阶段用
uv sync或poetry install --no-dev,它会读取锁文件并跳过解析 - 不再
COPY requirements.txt .,而是COPY pyproject.toml poetry.lock .(或requirements.lock) - 若必须保留
requirements.txt名称(比如某些平台强制要求),就把它当成锁文件别名,但内容必须带哈希、来源注释,并禁止手动编辑
真正难的不是换工具,是让所有人理解:依赖声明和依赖锁定必须分离,且锁定必须包含足够上下文。否则只是把 requirements.txt 换个名字,问题还在。






