pip高级用法与依赖管理

掌握Python包管理的进阶技巧

一、前言与概述

Python的包管理生态中,pip 是最基础也是最核心的工具。绝大多数开发者仅使用 pip install packagepip install -r requirements.txt 两条命令,但这远远没有发挥 pip 的全部能力。在真实项目中——尤其是多人协作、多环境部署、私有包管理场景下——深入了解 pip 的高级特性是区分"会用"和"精通"的关键分水岭。

本文将覆盖以下核心主题:requirements.txt 的高级格式语法(版本约束、环境标记、VCS引用)、pip freeze 与 pip list 的差异与适用场景pip install 关键选项(--no-deps、--no-build-isolation、--find-links、--extra-index-url)、依赖锁定与 pip-tools私有包索引与镜像源配置pipx 隔离安装Wheel 与源码分发的区别以及 pip 缓存管理

学习目标

  • 掌握 requirements.txt 的全部格式特性,能编写生产级依赖文件
  • 理解 pip 依赖解析机制,能诊断和解决依赖冲突
  • 学会使用 pip-tools 实现可复现的依赖锁定
  • 掌握私有包索引与多源配置,适应企业级开发环境
  • 理解 Wheel 与源码分发的区别,优化包安装性能

二、requirements.txt 高级格式

大多数开发者将 requirements.txt 视为简单的"包名+版本号"列表,但实际上 pip 支持的 requirements 文件格式远比这更丰富。

2.1 基础格式回顾

每一行定义一个依赖项,支持注释(以 # 开头)和空行。

基础 requirements.txt
# 这是注释 flask # 指定版本 requests==2.31.0 # 版本范围 numpy>=1.21.0, <2.0.0 # 排除版本 pandas!=1.4.0

2.2 版本约束符号详解

符号含义示例说明
==精确匹配django==4.2.0只安装该精确版本
>=大于等于python-dateutil>=2.8最低版本要求
>大于click>8.0排除该版本及之前版本
<小于urllib3<2.0上限约束(不常用)
<=小于等于pyyaml<=6.0上限约束
!=排除版本cryptography!=38.0.0跳过已知有问题的版本
~=兼容版本pydantic~=2.0等价于 >=2.0, ==2.*

~= 操作符是兼容版本约束(Compatible Release),其语义为"不低于指定版本且不超出下一个有序的不兼容版本"。例如 pydantic~=2.4.0 等价于 >=2.4.0, ==2.4.*,即允许 2.4.x 范围内的小版本升级,但不允许升级到 2.5.0 或 3.0.0。

2.3 环境标记(Environment Markers)

最强大但最容易被忽略的特性:可以根据目标平台、Python 版本等因素条件性地安装依赖

使用环境标记的 requirements.txt
# 仅 Python 3.10+ 需要 dataclasses; python_version >= "3.10" # 仅 Windows 需要 pywin32; sys_platform == "win32" # 仅 macOS 需要 pyobjc-framework-Cocoa; sys_platform == "darwin" # 仅 Linux 需要 python-prctl; sys_platform == "linux" # 仅 CPython 实现需要 cryptography; implementation_name == "cpython" # Python 3.9 以下使用 importlib_metadata 作为 backport importlib-metadata; python_version < "3.9" # 64 位架构需要 tensorflow; platform_machine == "x86_64" # 支持多个条件的复杂组合 pyside6; sys_platform == "win32" or sys_platform == "darwin" numpy>=1.21; platform_python_implementation != "PyPy"

支持的环境变量完整列表如下:

标记名称描述示例值
os_name操作系统名称nt, posix
sys_platform系统平台win32, linux, darwin
platform_machine机器架构x86_64, aarch64
platform_python_implementationPython 实现CPython, PyPy
platform_system系统名称Windows, Linux, Darwin
python_versionPython 版本3.10, 3.11
python_full_version完整 Python 版本3.10.12
implementation_name实现名称cpython, pypy
implementation_version实现版本3.10.12
extra额外特性名称test, dev

最佳实践:生产级 requirements.txt 示例

# requirements.txt - 生产环境 # 核心框架 fastapi>=0.100.0, <0.110.0 uvicorn[standard]>=0.23.0 # 数据库 sqlalchemy>=2.0, <2.1 asyncpg; sys_platform != "win32" # Windows 上没有 asyncpg aiosqlite; sys_platform == "win32" # 仅在 PyPy 下使用纯 Python 替代品 psycopg2-binary; platform_python_implementation == "CPython" psycopg2cffi; platform_python_implementation == "PyPy" # 异步支持 — 仅在 Python 3.11+ 不需要 backport exceptiongroup; python_version < "3.11" # 仅生产环境 gunicorn; sys_platform != "win32"

2.4 直接引用(Direct References)

使用 @ 语法可以直接指向一个具体的发行包 URL、本地路径或者 Wheel 文件,跳过 PyPI 查找过程。

直接引用格式
# 直接从 URL 安装 mypackage @ https://example.com/packages/mypackage-1.0.0-py3-none-any.whl # 从本地路径安装 mypackage @ file:///home/user/packages/mypackage-1.0.0.tar.gz # 使用相对路径(推荐在项目仓库内使用) mypackage @ ./vendor/mypackage-1.0.0-py3-none-any.whl # 从本地开发目录安装(可编辑模式) -e ./mypackage

2.5 VCS 引用(Version Control System References)

直接从 Git、Mercurial、Subversion 等版本控制系统安装包,对于依赖尚未发布的修复或私有仓库中的代码极为实用。

VCS 引用格式
# 从 Git 仓库安装(默认分支) git+https://github.com/author/mypackage.git # 指定分支 git+https://github.com/author/mypackage.git@main # 指定标签 git+https://github.com/author/mypackage.git@v1.2.3 # 指定 commit hash git+https://github.com/author/mypackage.git@abc123def456 # SSH 方式(需要配置 SSH 密钥) git+ssh://git@github.com/author/private-repo.git@main # 带子目录(当包位于仓库子目录中时) git+https://github.com/author/monorepo.git@main#subdirectory=packages/foo # 同时支持 -e 可编辑模式 -e git+https://github.com/author/mypackage.git@main

注意事项

  • VCS 引用在 pip freeze 输出中会保留完整 URL,可能会泄露私有仓库地址
  • CI/CD 环境中使用 SSH 引用需要妥善处理部署密钥
  • monorepo 场景下 subdirectory 参数非常有用,但要求 pip 版本 >= 21.3

三、pip freeze 与 pip list 深度对比

这两个命令常被混淆,但它们的用途完全不同。

特性pip freezepip list
输出格式package==version(可直接写入 requirements.txt)表格形式(包名 + 版本)
默认输出范围仅显示通过 pip 安装的包显示所有已安装包(含 setuptools、pip 自身)
常用选项--exclude(排除特定包)、--local--outdated--uptodate--format
主要用途生成 requirements.txt查看环境状态、检查更新

常用命令示例

# 生成当前环境的依赖列表 pip freeze > requirements.txt # 排除特定包(如不需要的测试框架) pip freeze --exclude pytest --exclude pytest-cov > requirements.txt # 只输出通过 pip 安装的包(排除 setuptools、pip 等) pip freeze --local > requirements.txt
pip list 命令
# 列出所有包 pip list # 仅列出有过期版本的包 pip list --outdated # 以 JSON 格式输出(方便程序解析) pip list --format=json pip list --outdated --format=columns # 列出最新版本的包 pip list --uptodate

重要区别

pip freeze 默认会输出所有依赖的传递依赖(transitive dependencies),而 pip list 展示环境中所有已安装的包。因此 pip freeze > requirements.txt 直接用于锁定文件是最方便的——但这也意味着它会包含许多你并未直接声明的包。

四、pip install 高级选项

以下选项在日常开发中容易被忽略,但在解决复杂依赖问题时不可或缺。

4.1 --no-deps:仅安装目标包,不安装依赖

当你只需要一个包的元数据(如 type stubs)或者依赖已通过其他方式满足时使用。

pip install mypy --no-deps

4.2 --no-build-isolation:禁用构建隔离

默认情况下,pip 在构建 wheel 时会在一个隔离环境中安装构建依赖。禁用后使用当前环境的构建依赖,这对需要系统级依赖(如 libpq-dev)的包很有用,也可以加速 CI 中的重复构建。

pip install psycopg2 --no-build-isolation

注意事项

--no-build-isolation 需要你已自行安装好所有构建依赖(如 setuptools、wheel、cython 等),否则构建可能失败。

4.3 --find-links:指定备选查找路径

可以指向本地目录HTML 页面(包含包下载链接),pip 会从中搜索包文件。

# 指向本地 Wheel 仓库 pip install --find-links ./wheelhouse mypackage # 指向私有索引页 pip install --find-links https://privateserver.com/packages/ mypackage # 也可以与 --index-url 组合使用 pip install \ --index-url https://pypi.org/simple/ \ --find-links https://private-packages.example.com/wheels/ \ mypackage

--find-links vs --index-url

  • --index-url:指定 PyPI 兼容的包索引(必须有 /simple 格式的 API)
  • --find-links:可以指向任何包含 Wheel/源码包的 URL 或本地目录
  • 同时使用时,pip 会先搜索 --find-links,再搜索 --index-url

4.4 --extra-index-url:添加额外包索引

当公司有私有 PyPI 服务器时,保留默认 PyPI 的同时添加私有源是非常常见的场景。

pip install mypackage \ --index-url https://pypi.org/simple/ \ --extra-index-url https://private-pypi.company.com/simple/

安全警告

--extra-index-url同时搜索多个源。如果私有源中找不到包,pip 会降级到公有 PyPI。攻击者可以通过在公有 PyPI 上注册一个同名依赖包来进行依赖混淆攻击(Dependency Confusion)。

防御方法:使用 --index-url 单独指向私有源,结合 --extra-index-url--find-links 来精确控制包的来源。

4.5 其他实用选项

# 限制并发下载数(默认 16) pip install --max-concurrent-downloads 8 # 仅使用二进制包(wheel),跳过源码构建 pip install --only-binary=:all: numpy # 强制从源码构建(不使用 wheel) pip install --no-binary numpy # 指定约束文件—允许限制依赖版本但不直接安装 pip install -c constraints.txt flask # 静默模式(不输出进度条,在 CI 中很有用) pip install -q package # 重试设置 pip install --retries 5 --timeout 30 package

约束文件 vs requirements 文件

约束文件(constraints file,通过 -c 参数指定)只限制版本,不引入新的包。这是与 requirements 文件的本质区别。常用于统一团队中多个项目的依赖版本范围。

# constraints.txt numpy>=1.22, <1.25 pandas>=1.4, <1.6 requests==2.31.0
# 使用约束文件 pip install -c constraints.txt flask fastapi

五、pip-tools 与依赖锁定

pip-tools 是 pip 生态中最流行的依赖锁定工具,受到 npmpackage-lock.json 启发,实现了 requirements.in + requirements.txt 双文件工作流。

5.1 安装 pip-tools

pip install pip-tools

5.2 基本工作流

步骤一:编写 requirements.in,只列出顶层依赖(top-level dependencies)。

requirements.in
# 只声明直接依赖 fastapi uvicorn[standard] sqlalchemy psycopg2-binary alembic redis

步骤二:使用 pip-compile 生成锁定后的完整依赖文件。

# 生成 requirements.txt(包含所有传递依赖的精确版本) pip-compile requirements.in # 指定输出文件 pip-compile requirements.in --output-file requirements.txt # 升级所有依赖到最新兼容版本 pip-compile --upgrade requirements.in # 只升级某个特定包 pip-compile --upgrade-package flask requirements.in # 生成带注释的输出(标注每个包来自哪个顶层依赖) pip-compile --annotate requirements.in

步骤三:使用 pip-sync 将当前环境与锁定文件精确同步。

# 同步环境(会卸载锁定文件中不存在的包!) pip-sync requirements.txt # 如果还在开发中,保留 pip 和 pip-tools pip-sync requirements.txt --pip-args "--no-deps"

5.3 pip-compile 输出示例

生成的 requirements.txt
# # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # pip-compile requirements.in # alembic==1.12.1 # via -r requirements.in anyio==4.1.0 # via starlette click==8.1.7 # via # uvicorn # alembic fastapi==0.108.0 # via -r requirements.in greenlet==3.0.1 # via sqlalchemy h11==0.14.0 # via uvicorn idna==3.6 # via anyio mako==1.3.0 # via alembic markupsafe==2.1.3 # via mako psycopg2-binary==2.9.9 # via -r requirements.in redis==5.0.1 # via -r requirements.in sniffio==1.3.0 # via anyio sqlalchemy==2.0.25 # via # -r requirements.in # alembic starlette==0.32.0.post1 # via fastapi typing-extensions==4.9.0 # via # fastapi # sqlalchemy # alembic uvicorn[standard]==0.25.0 # via -r requirements.in

pip-tools 的核心价值

  • 可复现性:锁定所有传递依赖的精确版本,确保不同环境完全一致
  • 可追溯性:注释标明每个包的来源,依赖关系一目了然
  • 安全更新:通过 --upgrade-package 精准控制升级范围
  • 分环境管理:可以为 dev、test、prod 分别维护不同的 .in 文件

5.4 多环境管理

requirements/dev.in
# 开发环境依赖 -c common.txt # 引用约束文件 -r base.in # 引用基础依赖 pytest>=7.0 pytest-cov pytest-asyncio black ruff mypy pre-commit
生成开发环境锁定文件
pip-compile requirements/dev.in --output-file requirements/dev.txt

六、依赖解析与冲突解决

6.1 pip 的依赖解析机制

从 pip 20.3(2020年底)开始,新版的依赖解析器(dependency resolver)被设为默认。其核心行为是回溯式解析(backtracking):当发现版本冲突时,会回溯并尝试其他版本组合,直到找到一组满足所有约束的版本——或者确认无解。

依赖解决过程示例

# 假设你运行: pip install "fastapi>=0.100" "sqlalchemy<1.4" # pip 的解析过程: # 1. 选中 fastapi 最新版(如 0.108.0) # 2. 发现 fastapi 依赖 pydantic>=1.7.4 # 3. 继续查看 sqlalchemy<1.4 的依赖 # 4. 检查所有这些依赖之间是否有版本冲突 # 5. 如果没有冲突,锁定所有版本 # 6. 如果有冲突,回溯尝试 fastapi 的旧版本 # 7. 重复直到找到可行组合或报告错误

6.2 常见冲突场景与解决方案

场景一:传递依赖冲突
# ERROR: Cannot install package-a==1.0 and package-b==2.0 # because these package versions have conflicting dependencies. # package-a 1.0 depends on shared-lib>=2.0 # package-b 2.0 depends on shared-lib<2.0 # 解决方案: # 1. 升级/降级 package-a 或 package-b 到兼容版本 # 2. 在约束文件中固定 shared-lib 的版本 pip install "package-a==1.1" "package-b==2.0"
场景二:使用约束文件缓解冲突
# constraints.txt shared-lib>=1.9, <2.1 pip install -c constraints.txt package-a package-b
场景三:查看冲突详情
# 使用 --verbose 获取详细的依赖解析过程 pip install package-a package-b --verbose # 使用 pipdeptree 可视化依赖树 pip install pipdeptree pipdeptree -p package-a

诊断依赖问题的工具链

  • pipdeptree:显示依赖树,快速定位冲突
  • pip check:验证当前环境中所有已安装包的依赖关系是否一致
  • pip install --dry-run:只解析依赖但不实际安装(pip 23.1+)
  • docker 镜像中的 pip list --outdated:定期检查过期的依赖
pipdeptree 输出示例
$ pipdeptree -p fastapi fastapi==0.108.0 - pydantic [required: >=1.7.4, !=1.8, !=1.8.1, !=2.0.0, !=2.0.1, !=2.1.0, installed: 2.5.2] - typing-extensions [required: >=4.6.1, installed: 4.9.0] - starlette [required: >=0.29.0, !=0.33.0, installed: 0.32.0.post1] - anyio [required: >=3.4.0, <5, installed: 4.1.0] - idna [required: >=2.8, installed: 3.6] - sniffio [required: >=1.1, installed: 1.3.0] - typing-extensions [required: >=4.8.0, installed: 4.9.0]

七、导出 requirements.txt 的最佳实践

团队协作中,一个精心维护的 requirements.txt 比口头约定的"大家都装什么版本"要可靠得多。以下是最佳实践建议。

推荐的多文件策略

# 项目依赖文件布局 requirements/ base.in # 基础依赖(生产共用) base.txt # 基础锁定文件(由 pip-compile 生成) dev.in # 开发依赖 dev.txt # 开发锁定文件 test.in # 测试依赖 test.txt # 测试锁定文件 ci.in # CI 依赖 ci.txt # CI 锁定文件 requirements.txt # 指向 base.txt 的符号链接或软引用

7.1 精确控制 vs 宽松约束

场景推荐方式原因
应用项目(Application)锁定精确版本保证可复现部署
库项目(Library)使用宽松版本范围兼容更多下游使用者
CI 环境锁定 + 定期自动升级平衡稳定性与安全性
开发环境锁定 + 手动升级团队成员间保持一致

7.2 导出简化技巧

# 仅导出顶层依赖(配合 pip-tools) pip-compile --no-annotate --no-header requirements.in # 移除 pip freeze 输出的某些包 pip freeze --exclude pip --exclude setuptools --exclude wheel # 在 CI 中检查 requirements 是否有变动 pip-compile --check requirements.in

7.3 不要提交 pip freeze 的直接输出

为什么不应直接使用 pip freeze > requirements.txt

  • 会包含当前环境的所有包(包括那些通过其他方式安装的)
  • 无法区分"直接依赖"和"传递依赖",导致升级困难
  • 不同平台上 freeze 结果可能不同(系统包混入)
  • 缺少与环境标记、安全更新相关的元信息

推荐做法:使用 pip-compile 生成锁定文件,同时保留 .in 文件用于声明顶层依赖。

八、私有包索引与镜像源配置

8.1 配置镜像源

在国内网络环境下,使用 PyPI 官方源时常遇到超时或速度缓慢的问题。配置镜像源是最直接的解决方案。

临时使用镜像源
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
全局配置镜像源
# Linux/macOS: ~/.config/pip/pip.conf # Windows: %APPDATA%\pip\pip.ini [global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple trusted-host = pypi.tuna.tsinghua.edu.cn # 也可以使用阿里云镜像 # index-url = https://mirrors.aliyun.com/pypi/simple/ # 或使用华为云镜像 # index-url = https://repo.huaweicloud.com/repository/pypi/simple/
在项目级别配置 pip.conf
# 项目根目录下放置 pip.conf [global] index-url = https://private-pypi.company.com/simple/ extra-index-url = https://pypi.tuna.tsinghua.edu.cn/simple/ trusted-host = private-pypi.company.com pypi.tuna.tsinghua.edu.cn

8.2 使用环境变量配置源

# 在 CI/CD 中使用环境变量覆盖默认源 export PIP_INDEX_URL=https://private-pypi.company.com/simple/ export PIP_EXTRA_INDEX_URL=https://pypi.org/simple/ export PIP_TRUSTED_HOST=private-pypi.company.com pip install -r requirements.txt

8.3 搭建私有 PyPI 源

企业内部通常需要私有包索引来托管业务相关的 Python 包。以下是几种主流方案。

使用 devpi 搭建
# 安装 devpi-server pip install devpi-server devpi-server --host 0.0.0.0 --port 3141 # 初始化 devpi devpi use http://localhost:3141 devpi login root --password="" devpi index -c dev bases=root/pypi # 上传包 devpi upload dist/mypackage-1.0.0-py3-none-any.whl
使用 pypiserver 搭建(更轻量)
# 安装 pypiserver pip install pypiserver # 启动服务(指向本地包目录) pypiserver --port 8080 --passwords=.htpasswd packages/ # 上传 Wheel 文件到 packages/ 目录即可 # 客户端配置 pip install --index-url http://pypi-server:8080/simple/ mypackage

推荐的企业解决方案对比

工具特点适用场景
devpi功能完整,支持镜像、缓存、测试索引中型团队,需要完整功能
pypiserver极简,基于文件系统小型团队或 CI 场景
Artifactory (JFrog)企业级,支持多种包格式大型企业,多语言产物管理
GitLab PyPI Registry与 GitLab CI 集成已在用 GitLab 的团队
AWS CodeArtifact云原生,自动伸缩AWS 用户

九、pipx:隔离安装 Python 应用

pipx 是一个专门用于安装和运行 Python 终端应用的工具。它会为每个应用创建独立的虚拟环境,避免应用依赖污染全局环境或相互冲突。

安装 pipx
# 推荐方式 pip install pipx pipx ensurepath # macOS brew install pipx # Linux (apt) sudo apt install pipx
pipx 常用命令
# 安装应用(自动创建隔离环境) pipx install poethepoet pipx install black pipx install ruff pipx install cookiecutter # 临时运行应用而不安装 pipx run pycowsay "Hello, pipx!" # 列出已安装的应用 pipx list # 升级应用 pipx upgrade-all # 卸载 pipx uninstall poethepoet # 从 GitHub 直接运行 pipx run https://github.com/author/repo.git # 查看 pipx 管理的所有环境 pipx list --verbose

何时使用 pipx 而不是 pip

  • 应该用 pipx:全局安装 CLI 工具(black、mypy、poetry、httpie、jupyter-lab 等)
  • 应该用 pip:在项目虚拟环境中安装库依赖
  • 注意:pipx 适合应用,不适合

十、Wheel vs Source Distribution

10.1 核心概念

特性Wheel(.whl)Source Distribution(sdist, .tar.gz)
本质预构建的二进制分发格式源码包,需要构建步骤
安装速度快(本质是解压 + 复制)慢(需要解压 + 可能编译)
构建依赖不需要构建工具需要 setuptools、wheel 等
是否编译已编译的 .so/.pyd 文件需要编译 C 扩展
平台相关有平台标签(如 win_amd64大部分是纯 Python 或跨平台
Python 版本有 ABI 标签(如 cp311通常不限 Python 版本
查看包的 wheel 标签
# numpy 的 wheel 文件命名示例 numpy-1.26.2-cp311-cp311-win_amd64.whl # ^^^^^ ^^^^^ ^^^^^^^^^^^ # 版本 Python ABI 平台 # 纯 Python 包(跨平台) requests-2.31.0-py3-none-any.whl # ^^^ ^^^^ ^^^ # py3 无ABI 跨平台

10.2 创建与分发

构建 Wheel
# 传统方式 pip install wheel python setup.py bdist_wheel # 现代方式(推荐) pip install build python -m build --wheel # 构建源码包 + wheel python -m build
安装时的选择优先级
# pip 默认优先选择 wheel(更快) # 强制使用 wheel(禁用源码构建) pip install --only-binary=:all: numpy # 强制从源码构建 pip install --no-binary numpy

10.3 理解平台兼容性

Manylinux 标准
# manylinux 标签说明兼容的 Linux 发行版范围 numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.whl # ^^^^^^^^^^^^^^^^^^^^^^^^^ # manylinux_2_17 = 兼容 glibc 2.17+ # x86_64 = 64 位 x86 架构 # 查看当前系统的 manylinux 兼容性 pip debug --verbose | findstr manylinux # Windows pip debug --verbose | grep manylinux # Linux/macOS

关键知识点

  • 纯 Python 包(如 requests、click):使用 py3-none-any 的通用 wheel,任何平台和 Python 3 版本都可安装
  • 含 C 扩展的包(如 numpy、pandas):需要平台特定 wheel,PyPI 为常见平台提供预编译包
  • 无可用 wheel 时:pip 自动回退到 sdist,但需要编译环境(gcc/msvc 等)
  • 企业建议:在私有源中同时发布 wheel 和 sdist,优先使用 wheel

十一、pip 缓存管理

pip 会缓存下载的包文件,避免重复下载同名文件。高效管理缓存可以显著加速 CI/CD 构建过程。

11.1 缓存目录位置

# Linux/macOS ~/.cache/pip/ # Windows %LocalAppData%\pip\Cache\ # 查看当前缓存路径 pip cache info # 输出示例 # Package index page cache location: ... # Package cache location: ... # Wheel cache location: ...

11.2 缓存管理命令

# 查看缓存大小 pip cache info # 列出所有缓存的 wheel pip cache list pip cache list --format=abspath # 删除所有缓存 pip cache purge # 删除指定包的缓存 pip cache remove numpy # 在 CI 中暖缓存(CI 构建前先下载但不安装) pip download -r requirements.txt --dest /tmp/pip-cache-warm

11.3 CI/CD 中的缓存策略

GitHub Actions 示例
# .github/workflows/ci.yml - name: Cache pip uses: actions/cache@v3 with: path: ~/.cache/pip key: pip-${{ runner.os }}-${{ hashFiles('requirements/*.txt') }} restore-keys: | pip-${{ runner.os }}- pip- - name: Install dependencies run: | pip install --upgrade pip pip install -r requirements/dev.txt
GitLab CI 示例
# .gitlab-ci.yml cache: key: ${CI_COMMIT_REF_SLUG} paths: - .cache/pip before_script: - export PIP_CACHE_DIR="$(pwd)/.cache/pip" - pip install -r requirements.txt

缓存优化建议

  • 在 CI 中将缓存 key 与 requirements 文件哈希绑定,只在依赖变更时重建缓存
  • 使用 --no-index --find-links 配合预下载的 wheel 目录,实现完全离线的安装流程
  • 定期执行 pip cache purge,避免缓存无限制增长
  • 对于大型 monorepo,考虑使用 PIP_NO_CACHE_DIR=0 显式启用缓存(默认就是启用的)

十二、完整实战案例

以下是一个真实项目的依赖管理全过程,综合运用本文介绍的各种技术。

场景:从零搭建一个 FastAPI 微服务项目

步骤 1:创建项目结构

myproject/ requirements/ base.in dev.in test.in ci.in pyproject.toml src/ tests/

步骤 2:编写顶层依赖

requirements/base.in
# 生产依赖 fastapi>=0.100.0 uvicorn[standard]>=0.23.0 sqlalchemy>=2.0 asyncpg==0.29.0 alembic>=1.12 redis>=5.0 pydantic-settings>=2.0 httpx>=0.25 # HTTP 客户端 python-jose[cryptography]>=3.3 # JWT 认证

步骤 3:生成锁定文件

pip-compile requirements/base.in --output-file requirements/base.txt pip-compile requirements/dev.in --output-file requirements/dev.txt

步骤 4:配置镜像源

# pip.conf [global] index-url = https://pypi.tuna.tsinghua.edu.cn/simple/ trusted-host = pypi.tuna.tsinghua.edu.cn

步骤 5:配置 CI 缓存

# .github/workflows/ci.yml (关键片段) jobs: build: steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.12" cache: pip cache-dependency-path: requirements/*.txt - run: pip install -r requirements/dev.txt

步骤 6:开发工具使用 pipx 安装

pipx install black ruff poethepoet mypy pre-commit

步骤 7:定期自动升级依赖

# 使用 Dependabot 或 Renovate 自动创建 PR 升级依赖 # .github/dependabot.yml version: 2 updates: - package-ecosystem: pip directory: "/requirements" schedule: interval: weekly open-pull-requests-limit: 5

十三、核心要点总结

十四、进一步思考

从 pip 到现代包管理生态

深入了解 pip 之后,可以进一步探索以下工具和概念:

  • Poetry:基于 pyproject.toml 的现代包管理工具,自动处理依赖锁定和环境管理
  • PDM:Python 开发与依赖管理工具,支持 PEP 517/518 标准,锁定文件格式为二进制
  • uv:Rust 编写的极速包管理工具(pip/venv 替代品),安装速度比 pip 快 10-100 倍
  • Conda:不仅管理 Python 包,还能管理系统级二进制依赖(常用于数据科学)
  • PEP 668:标记系统级 Python 环境,阻止 pip 直接安装到系统环境中,强制执行虚拟环境

学习路径建议

  • 入门:掌握 requirements.txt 全语法 + pip freeze/list 差异
  • 进阶:学会 pip-tools 工作流 + 多环境依赖管理 + 私有源配置
  • 高级:理解 Wheel 构建与分发 + 自定义 pip 插件 + 依赖解析算法