🐍 Day 10: 依赖管理 — 从 requirements.txt 到 pyproject.toml

📖 知识点简介

项目写大了,依赖管理就成了刚需。今天带你绕开 Python 依赖管理的经典雷区:搞清楚 requirements.txt 的江湖地位、体验 uv 这个下一代包管理器的闪电速度、搞懂私有源怎么配、离线包怎么装、以及终极方案 pyproject.toml 的统一标准。


1️⃣ requirements.txt --- 最朴素的依赖锁

基础用法

txt 复制代码
# requirements.txt
requests>=2.28.0
flask==2.3.3
numpy~=1.25.0   # 兼容 >=1.25.0, <1.26.0
pandas<2.0.0
bash 复制代码
# 安装
pip install -r requirements.txt

# 导出当前环境的依赖
pip freeze > requirements.txt

# 只导出顶层依赖(推荐,pip 无原生支持,用 pip-tools)
pip install pip-tools
pip-compile requirements.in  # 自动生成 requirements.txt(含所有传递依赖)

🚨 避坑:pip freeze 三大陷阱

| 陷阱 | 问题 | 正确做法 |
|----------|------------------------|----------------------------------------|------------------------------------|
| 全量导出 | 连 pip、setuptools 都写进去了 | 用 `pip freeze | grep -v "^pip|^setuptools"` 过滤 |
| 无顶层/传递区分 | 100 行依赖,不知道哪些是直接装的 | 用 pip-compile 或直接写 requirements.in |
| 无哈希校验 | 坏人篡改包版本,pip 不检查 | 用 pip freeze --hash 生成带哈希版本 |

生产级的分组方案

csharp 复制代码
requirements/
├── base.txt          # 公共依赖
├── dev.txt           # 开发时额外依赖
│   └── -r base.txt   # 继承 base
├── test.txt          # 测试依赖
│   └── -r base.txt
└── prod.txt          # 生产依赖(锁定精确版本)
    └── -r base.txt
txt 复制代码
# requirements/dev.txt
-r base.txt
pytest>=7.0
black>=23.0
pdbpp>=2.0

2️⃣ pyproject.toml --- 现代 Python 的标准

PEP 621 把项目元数据统一到 pyproject.toml。不管用 pip、poetry、uv、pdm,共享同一份配置。

基本结构

toml 复制代码
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "my-awesome-app"
version = "0.1.0"
description = "一个超棒的应用"
requires-python = ">=3.11"
dependencies = [
    "requests>=2.28",
    "flask>=2.3,<3.0",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7",
    "black>=23",
    "ipython",
]
test = [
    "pytest-cov>=4",
    "pytest-mock>=3",
]

安装依赖

bash 复制代码
# pip 从 pyproject.toml 安装(pip 21.3+)
pip install -e .                    # 可编辑安装(开发模式)
pip install ".[dev]"               # 安装 + dev 可选依赖
pip install ".[dev,test]"          # 多组可选依赖

🚨 pyproject.toml vs setup.py

arduino 复制代码
            pyproject.toml                      setup.py
     ┌──────────────────────┐        ┌────────────────────────┐
     │  声明式(声明"要什么")│        │ 命令式(描述"怎么装") │
     │  可读性好、无副作用   │        │ 可以写 Python 代码    │
     │  标准统一、推荐方案    │        │ 历史遗留、逐渐淘汰     │
     └──────────────────────┘        └────────────────────────┘

金科玉律 :新项目只写 pyproject.toml。除非你要写复杂的 C 扩展构建逻辑,才需要保留 setup.py


3️⃣ uv --- 下一代包管理器(⚡ 快 10-100 倍)

uv 是 Rust 写的 pip 替代品,兼容 pip 的 requirements.txtpyproject.toml

安装 uv

bash 复制代码
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# 或者用 brew(推荐)
brew install uv

常用命令

bash 复制代码
# 创建虚拟环境(比 venv 快 50 倍)
uv venv .venv

# 安装依赖(自动创建 venv)
uv pip install requests flask

# 从 requirements.txt 安装
uv pip install -r requirements.txt

# 从 pyproject.toml 安装
uv pip install -e .

# 锁定精确版本(生成 uv.lock)
uv lock

# 根据 lock 文件同步环境
uv sync

# 导出为 requirements.txt
uv pip freeze > requirements.txt

# 升级所有包
uv pip sync requirements.txt

uv lock 的优势

bash 复制代码
# 1. 生成 uv.lock(包含哈希校验和传递依赖)
uv lock

# 2. 别人拉代码后,一秒恢复一模一样的环境
uv sync

对比传统 pip + pip freeze

场景 pip uv
首次安装 100 个包 ~30s ~1s
lock 文件生成 pip-tools 手动 uv lock 一键
依赖解析 慢(纯 Python) 快(Rust 并行)
哈希校验 需手动 --hash 默认全量校验

4️⃣ 私有源(Custom Index)

公司内部包或镜像源怎么配?用 --index-urlPIP_INDEX_URL 环境变量。

命令行方式

bash 复制代码
# 临时替换为清华镜像
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# uv 版
uv pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

配置文件方式(推荐)

ini 复制代码
# ~/.pip/pip.conf 或项目根目录 pip.conf
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
trusted-host = pypi.tuna.tsinghua.edu.cn

[install]
# 额外附加的私有源
extra-index-url =
    https://my.company.com/pypi/simple/

私有源认证

bash 复制代码
# 方式 1:URL 嵌入用户名密码
pip install my-internal-lib \
  -i https://user:password@private.pypi.local/simple/

# 方式 2:keyring 集成(推荐,密码存系统钥匙串)
pip install keyring
# 首次会提示你输入,之后自动读取

🚨 避坑:私有源加 --trusted-host

如果没有 HTTPS 证书,需要手动信任:

bash 复制代码
pip install my-pkg --trusted-host private.pypi.local

否则出现 Unverified HTTPS request 警告。


5️⃣ 离线包安装(在公司内网或无网络环境)

场景 A:有网机器下载,无网机器安装

下载阶段(有网机器)

bash 复制代码
# 下载所有依赖到 offlin_pkgs/ 目录
pip download -r requirements.txt -d offline_pkgs/
# uv 版
uv pip download -r requirements.txt --target offline_pkgs/

安装阶段(无网机器)

bash 复制代码
# 从本地目录安装,不联网
pip install --no-index --find-links=./offline_pkgs/ -r requirements.txt

场景 B:把整个 PyPI 镜像到本地

bash 复制代码
# 使用 bandersnatch 同步完整镜像(不常用,适合企业)
pip install bandersnatch

场景 C:单文件 Wheel 安装

bash 复制代码
# 你已经下载了 .whl 文件
pip install requests-2.31.0-py3-none-any.whl

⚡ 避坑 & 要点总结

# 要点 说明
1️⃣ 永远用虚拟环境 python -m venv .venv 是最低要求,别污染系统 Python
2️⃣ 生产环境锁定版本 requirements-prod.txt 必须锁到 patch 版本号
3️⃣ pip freeze 有坑 全量导出含无关包,用 pip-compileuv lock
4️⃣ 新项目用 pyproject.toml 别写 setup.py 了,除非有 C 扩展
5️⃣ uv 是 pip 的超集 可以逐步迁移,命令几乎 1:1 对应
6️⃣ 私有源配 extra-index-url 同时保留公共源和私有源
7️⃣ 离线包用 --no-index 配合 --find-links 离线部署
python 复制代码
# 调试小技巧:看看当前环境安装了哪些包、版本和位置
import pkg_resources

for pkg in sorted(pkg_resources.working_set, key=lambda x: x.key):
    print(f"{pkg.key:25s} {pkg.version:15s} {pkg.location}")
相关推荐
学长毕业设计1 小时前
基于SpringBoot的校园二手物品交易系统(源码+文档+讲解视频)
java·spring boot·后端
2601_962294051 小时前
Python 操作 Word:如何查找、替换和批量修改文本
python·正则表达式·word·文档处理·查找替换
Darling噜啦啦1 小时前
从 SSE 到 LLM 流式输出:搞懂前端实时通信的两种姿势
前端·后端·llm
wangfpp1 小时前
原生NodeJS维护Agent Memory实践
后端·agent·全栈
星月日1 小时前
前端上手后端起手式
前端·后端
掘金挖土1 小时前
前端手摸手跑路之 AI 应用开发(一)
前端·后端
weixin_440730502 小时前
allure总结--解决版本不相容,没有trend(生成原始报告+复制history后在一起生成新报告)+jenkins集成
python·测试报告·allure
小柯南敲键盘2 小时前
跨马翻译:图片翻译软件批量处理,跨境电商视频字幕AI智能抠图
人工智能·python·音视频
BYSJMG2 小时前
计算机毕业设计选题推荐|【基于大数据的植被光谱特征与环境因子关联分析及可视化】Spark+K-Means
大数据·python·信息可视化·数据分析·spark·kmeans·课程设计