>>>PyPathPython 学习站
首页›核心篇›kp-021
核心篇 · Core lv.2 核心 kp-021

虚拟环境与依赖管理

前置知识:kp-002、kp-014

1. 一句话定义

虚拟环境(venv)为每个项目提供独立的解释器视图 + 独立的第三方包目录;依赖声明进 pyproject.toml,锁定版本生成 lock 文件——这是 Python 项目可复现的最小闭环。

2. 为什么重要

"项目 A 要 requests 2.x、项目 B 要 3.x"在同一解释器下不可解。虚拟环境把依赖隔离到项目级,是所有现代工具(uv/poetry/pipenv)共同的底层思想。

3. 前置知识

kp-002(解释器与 PATH)、kp-014(模块查找)。

4. 核心概念

  • venv 目录:python3 -m venv .venv 生成;内含指向基础解释器的链接 + 独立 site-packages。
  • 激活:source .venv/bin/activate 把 .venv/bin 排到 PATH 首位(deactivate 退出)。
  • pip 闭环:pip install → 写入环境 + pip freeze > requirements.txt。
  • pyproject.toml(PEP 621):项目元数据 + 依赖声明的标准文件,取代旧 setup.py。
  • uv(现代首选):uv add、uv sync、uv.lock,比 pip 快一个数量级且自动管理 venv。

5. 原理与机制

bash
# 传统 pip 流程
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install requests
pip freeze > requirements.txt      # 快照当前环境(含间接依赖)
pip install -r requirements.txt    # 复现

# uv 流程(推荐)
uv init                            # 生成 pyproject.toml
uv add requests                    # 声明 + 安装 + 更新 lock
uv sync                            # 按 lock 精确重建环境
uv run python script.py            # 无需手动激活

venv 的本质:.venv/bin/python 是一个会优先查 .venv/lib/pythonX.Y/site-packages 的解释器入口—— kp-014 的 sys.path 多了一条项目专属路径而已。

6. 关键事实(模型/图示)

text
系统解释器 ──共享──► /usr/lib/python3/site-packages     ← 别动
      │
      └── .venv/ ──► .venv/lib/.../site-packages        ← 项目专属
                      ↑ pip/uv 只写这里
依赖三层概念:
  声明(pyproject: 我需要 requests>=2)→ 锁定(uv.lock: 2.32.3 具体版本)
  → 安装(site-packages 里的实际代码)

7. 直观类比

虚拟环境是每道菜的独立料理台:砧板调料互不串味(依赖隔离);pyproject.toml 是菜谱(用什么料),lock 是采购单(哪个牌子哪一批次),照单采购(sync)才能做出一模一样的菜。

8. 实例与案例

bash
# 排查"装了却 import 不到"
which python3            # 用的是哪个解释器?
python3 -c "import sys; print(sys.prefix)"   # 是否在 .venv 里
pip show requests        # 装到了哪个 site-packages

三连问能解决 90% 的"环境玄学"。

9. 常见误区

  1. 激活了 A 项目环境却在 B 项目工作 —— 检查提示符前缀 ( .venv );或干脆用 uv run 避免手动激活。
  2. 只提交 requirements 不提交 lock —— freeze 快照与 lock 解析可复现是两码事;团队/CI 用锁定文件。
  3. 把 .venv 提交进 git —— 它含平台相关二进制;.gitignore 掉。
  4. 直接 pip install 进系统/Conda base —— PEP 668 后新版发行版会拒绝(externally-managed-environment);本来就该隔离。

10. 自测题

  1. venv 里 import requests 能找到包的完整链路是什么?
  2. requirements.txt 与 uv.lock 的本质区别?
  3. "装了却 import 不到"的三步排查?
参考答案
  1. 当前 python 的 sys.path 指向 .venv 的 site-packages → 该目录里有 requests → 正常导入;反之若解释器不在 .venv,则查的是别的 site-packages。
  2. freeze 是"当前环境快照"(环境相关、顺序无保证);lock 是"依赖解析的确定性结果"(跨平台可复现、含哈希)。
  3. 见实例与案例:which / sys.prefix / pip show。

11. 与其他知识点的关系

  • kp-036 打包与发布:把项目变成可安装包。
  • kp-045 工程规范:环境配置进 CI 的标准做法。
  • kp-002 版本管理:解释器版本与环境是两层。

12. 延伸阅读

  • Python Packaging User Guide(virtualenvs 章节)
  • uv 文档:https://docs.astral.sh/uv/concepts/projects/