前置知识: 零基础起步

Python 环境工具全景:venv/uv/poetry/conda 怎么选

7 min入门

以「接手一个工具各异的团队仓库」为场景,横向看清 venv、virtualenv、pip、poetry、conda、uv 的分工与取舍:靠锁文件识别项目工具链、各工具核心命令、pip 与 uv 的数量级差距、conda 管非 Python 依赖的独特价值,附新项目决策清单与跨语言对照。

前置知识

  • 已读完 虚拟环境:会创建与激活 .venv,知道 requirements.txt 的角色;
  • 最好也翻过 pyenv 与 uv 版本管理:知道「解释器版本」与「依赖」是两层问题。

你现在要解决什么问题

你入职第一天拉下团队仓库,发现三个项目三副面孔:老脚本是 requirements.txt + venv;后端服务用 poetry(pyproject.toml + poetry.lock);新写的工具用 uv(uv.lock)。同事 A 说「都 2026 年了直接 uv」,同事 B 说「数据科学那套还是 conda 稳」。你没跑过这些工具,根本插不上话。

这篇不教你再装一遍环境(040 已教),只解决三件事:拿到一个陌生项目,怎么一眼看出它用哪套工具;每套工具的最小命令集长什么样;新项目你自己该选哪个。

第一步:靠文件指纹认出工具链

不用问人,看仓库根目录的文件组合:

你看到它在说进场命令
只有 requirements.txt传统 pip + venv 流python -m venv .venv 激活后 pip install -r requirements.txt
pyproject.toml + poetry.lockpoetry 项目poetry install,日常 poetry add / poetry run
pyproject.toml + uv.lockuv 项目uv sync,日常 uv add / uv run
pyproject.toml + uv.lock + .python-versionuv 全家桶(连解释器也管)uv sync 会自动装对版本的 Python
environment.ymlconda 项目(多见于数据科学)conda env create -f environment.yml
只有散落的 .py个人小脚本建议你按 040 自己补一个 venv

原则一条:装依赖之前先认锁文件,跟着锁文件走。在有 uv.lock 的项目里手滑 pip install,会把环境弄成与锁文件不一致的状态,同事拉代码后必炸。

工具全景表:谁在哪个位置

历史脉络一句话:venv(2012 进标准库)解决隔离;pip 解决装包;两者都不管「依赖冲突的求解」与「锁文件」,于是 poetry(2018)把「项目 + 依赖解析 + 锁定」打包;uv(2024,Rust 实现)把这一整条链重写了一遍,速度拉开数量级,2025 年起成为新项目默认答案。conda 是另一条独立路线,下面单说。

工具隔离依赖解析锁文件速度管 Python 版本管 C/CUDA 等非 Python 依赖
venv + pip是无(pip 只管装)无(手写 requirements)基准否否
virtualenv是无无较快可指定任意版本创建否
poetry是是(resolvelib)poetry.lock慢弱(配 pyenv)否
conda / pixi是是(SAT / PubGrub)environment.yml / 锁慢 / 快是是(独门)
uv是是(PubGrub)uv.lock极快是(自动下载)否

两个容易被追问的点:

  • virtualenv 还有人用吗:它是 venv 的「前辈 + 增强版」,创建更快、能指定任意解释器建环境;venv 进标准库后,多数场景被 venv 取代,需要跨版本建环境时仍会碰到它。
  • rye / pdm / hatch 呢:同代项目管理器,uv 出现后生态快速收敛(rye 团队已并入 uv 项目)。知道名字即可,不必投入。

速度差距是真实的:一次冷装实测

从空环境装同一组常用包(fastapi、sqlalchemy、pytest 等约 50 个传递依赖),数量级感受一下:

text
pip           冷装约 18-22 秒     热缓存约 12-16 秒
poetry        冷装约 29 秒        热缓存约 20 秒
uv            冷装约 1.2 秒       热缓存约 0.3 秒

差距来源不是魔法:uv 用 Rust 重写了下载、解压与解析(并行 + 全局缓存 + PubGrub 求解算法),并且全局缓存意味着第二个项目装同一批包几乎是本地复制。CI 里这个差距乘以每次构建,就是团队真实省下的时间。

conda 的独特位置:管到 Python 之外

conda 常被误当成「另一个 pip」。它真正的不可替代性在最后一列:能安装非 Python 依赖。装一个深度学习环境时,numpy 加速底层的 MKL、GPU 相关的 CUDA 运行库、编译工具链,这些不是 Python 包,pip 装不了或装得半身不遂;conda(及 Rust 重写的后继者 pixi)把它们和 Python 包一起求解、一起装好。所以:

  • 纯 Python 项目:用不着 conda,它反而更慢更重;
  • 数据科学 / 深度学习 / 科学计算:conda 系仍是省心解,尤其要特定 CUDA 版本时。

各工具最小命令集

poetry(认准「声明在 pyproject、锁在 poetry.lock、跑在 poetry run 里」):

bash
poetry init                    # 交互式生成 pyproject.toml(老项目接入)
poetry new mypkg               # 新建标准项目骨架
poetry add fastapi             # 安装并写入依赖
poetry add pytest --group dev  # 开发依赖分组
poetry install                 # 按锁文件精确安装
poetry env use python3.12      # 指定解释器建环境
poetry run python main.py      # 在项目环境里运行
poetry build && poetry publish # 构建 sdist/wheel 并发 PyPI

conda(环境在 conda 眼里是「有名字的」):

bash
conda create -n dl python=3.12        # 建名为 dl 的环境
conda activate dl                     # 激活(注意不是 source)
conda env create -f environment.yml   # 按文件重建
conda install pytorch torchvision     # 装 conda 仓库的包(含二进制依赖)
conda deactivate

uv(命令在 030 与 040 已系统学过,这里只列项目管理姿势):

bash
uv init myproject      # 生成 pyproject.toml 骨架
uv add fastapi         # 声明并安装,锁进 uv.lock
uv sync                # 按锁文件精确重建(会自动装 .python-version 指定的解释器)
uv run python main.py  # 环境内运行,无需手动激活
uv run --with httpx python -c "import httpx"   # 临时依赖跑一次性任务

动手实验:把 040 的 venv-lab 项目用 uv init 重做一遍,对比生成的 pyproject.toml 与你手写的 requirements.txt——前者声明「直接依赖」,锁文件记「全部精确版本」,分工更清楚。

新项目怎么选:一张决策卡

按顺序问自己:

  1. 要装 CUDA / MKL 这类非 Python 依赖吗?要,conda 或 pixi;不要,继续;
  2. 是一个人的小脚本?venv + pip 足够,别为脚本引入工具链;
  3. 是要长期维护、多人协作、要发布的项目?uv(2026 年新项目的默认答案:快、锁文件、连解释器一起管、monorepo 友好);
  4. 团队已经在用 poetry?跟着团队,工具一致性大于工具先进性。想提速可以只把安装环节换成 uv pip install(读 poetry.lock 之外的场景慎用,别破坏锁状态)。

迁移提示:poetry 转 uv 有成熟的 uv sync 兼容路径,但不要在项目半路换工具而不通知团队——锁文件是协作契约。

跨语言视角:Python 的 venv 是特例吗

语言包管理隔离方式锁文件
Node.jsnpm / pnpmnode_modules(项目本地)package-lock.json
Rustcargo自动(编译期隔离)Cargo.lock
Gogo mod模块路径隔离go.sum
Pythonpip / uv / poetry显式虚拟环境requirements / *.lock

多数现代语言靠「项目本地依赖目录 + 全局缓存」天然隔离,不需要你显式「激活」什么。uv 正在把 Python 往 cargo 这个体感拉近(自动管理环境、无感切换),但只要团队里还有 pip 用户,显式虚拟环境仍是 Python 的通用语。理解了这一点,你就明白为什么本文有这张表,而 Go 的教程没有。

自我检查

  • 拿到陌生仓库,能凭文件组合说出工具链与进场命令;
  • 能说出 uv 快的三个来源(Rust 重写、全局缓存、现代求解算法);
  • 能解释 conda 与 pip 的本质区别(是否管非 Python 依赖);
  • 新项目能按决策卡给出选择并说明理由。

练习

预测题:在一个有 uv.lock 的项目里直接 pip install requests,uv sync 之后再 pip list,requests 还在吗?动手验证(提示:uv sync 会把环境恢复到锁文件状态)。

修改题:把一个只有 requirements.txt 的老项目接入 uv:uv init 后用 uv add -r requirements.txt 批量迁移直接依赖,观察 pyproject.toml 与 uv.lock 的生成。

排错题:同事报告「在你这个 poetry 项目里 poetry install 报 lock 过期」。为什么会发生?两个标准修法是什么(poetry lock --no-update 重新生成锁 / 提交前先 poetry install 自检)?

挑战题:为你的团队写一页 CONTRIBUTING 环境指引:新成员按工具链判断表进场,附每条命令的预期输出。写完发给一位没接触过 Python 的朋友试跑,收集卡点。

下一步