3、包管理器入门:pip、conda与poetry的对比与选择
说到环境配置,包管理器就是你的「后勤部长」。选对了,后面省心;选错了,够你折腾半天。
我刚开始做深度学习那会儿,觉得包管理器不就是个装包的工具嘛,哪个顺手用哪个。结果呢?项目一多,环境乱成一锅粥。今天这个包冲突,明天那个版本不对,光排查依赖问题就能耗掉一上午。
后来我花了点时间,把 pip、conda、poetry 这三个主流工具摸透了。说实话,它们各有各的脾气,没有的「最好」,只有「最合适」。今天我就把这三兄弟的底细给你掰扯清楚。
一句话总结:pip 是 Python 生态的「标配」,conda 是数据科学家的「瑞士军刀」,poetry 是项目级依赖管理的「管家」。
3.1 pip:Python 的默认选择
pip 是 Python 官方推荐的包管理器,只要你装了 Python,它就跟着来了。简单、直接、生态最全。
它的核心逻辑是:从 PyPI(Python Package Index)下载包,然后安装到当前环境。PyPI 上有超过 40 万个包,基本上你能想到的库,上面都有。
# 安装包
pip install numpy
# 指定版本
pip install torch==2.0.1
# 从 requirements.txt 安装
pip install -r requirements.txt
# 导出当前环境的包列表
pip freeze > requirements.txt
但 pip 有个硬伤——它不解决依赖冲突。什么意思呢?假如包 A 依赖 numpy<1.20,包 B 依赖 numpy>=1.20,pip 会直接报错,或者装一个「看起来能用」的版本,然后运行时炸给你看。
我曾经踩过的坑:用 pip 装了一个项目,本地跑得好好的,部署到服务器上就报 ImportError。查了半天,发现是 pip freeze 导出的 requirements.txt 里,有些包的版本号没锁死,服务器上装了更新的版本,接口变了。从那以后,我养成了手动锁定所有依赖版本的习惯。
pip 适合什么场景?
- 快速实验、写个小脚本
- 项目依赖简单,没有复杂的版本冲突
- 你只需要 Python 包,不需要管理非 Python 的依赖
3.2 conda:数据科学家的首选
conda 是 Anaconda 发行版自带的包管理器。它跟 pip 最大的区别是:conda 不仅能管 Python 包,还能管 C 库、R 包、甚至系统级的二进制文件。
你想想看,深度学习里常用的 CUDA、cuDNN、OpenCV 这些,底层都是 C/C++ 写的。用 pip 装这些,经常要手动编译,或者依赖系统里已经装好的库。而 conda 直接给你提供预编译好的二进制包,省去了编译的麻烦。
# 创建环境
conda create -n myenv python=3.9
# 激活环境
conda activate myenv
# 安装包
conda install numpy pandas
# 从 channel 安装(比如 conda-forge)
conda install -c conda-forge opencv
# 导出环境
conda env export > environment.yml
# 从 yml 文件创建环境
conda env create -f environment.yml
conda 还有一个杀手锏——环境隔离。每个 conda 环境都是独立的,互不干扰。你可以在一个环境里装 PyTorch 1.13,另一个环境里装 PyTorch 2.0,切换起来毫无压力。
| 特性 | pip | conda |
|---|---|---|
| 包来源 | PyPI | Anaconda 仓库 / conda-forge |
| 支持非 Python 包 | 否 | 是(C 库、二进制文件等) |
| 依赖冲突解决 | 弱(不自动解决) | 强(SAT 求解器) |
| 环境管理 | 需配合 venv/virtualenv | 内置 |
| 包数量 | ~40 万 | ~2 万(但覆盖主流数据科学库) |
| 安装速度 | 快(直接下载 wheel) | 中等(需解析依赖树) |
我的建议:如果你主要做深度学习、数据分析、科学计算,直接用 conda。它帮你省掉了很多底层依赖的麻烦。我个人习惯用 Miniconda(轻量版 Anaconda),只装必要的包,不浪费磁盘空间。
3.3 poetry:现代项目的依赖管家
poetry 是近几年火起来的包管理器。它解决了一个 pip 和 conda 都没做好的问题——项目级依赖的精确锁定和可复现性。
什么意思呢?你用 pip freeze 导出的 requirements.txt,只记录了「当前环境里装了哪些包」,但没记录「这些包之间的依赖关系」。换一台机器,用同样的 requirements.txt 安装,可能因为某些依赖的版本不同,导致行为不一致。
poetry 用 pyproject.toml 和 poetry.lock 两个文件来解决这个问题:
pyproject.toml:声明你的项目直接依赖了哪些包(比如 torch、numpy)poetry.lock:锁定所有依赖(包括间接依赖)的精确版本号
# 初始化项目
poetry init
# 添加依赖
poetry add torch numpy
# 安装所有依赖(根据 lock 文件)
poetry install
# 更新依赖
poetry update
# 导出 requirements.txt(给 pip 用)
poetry export -f requirements.txt --output requirements.txt
poetry 还有一个好处——自动创建虚拟环境。你不需要手动 python -m venv,poetry 会自动帮你建好,并且把包装到虚拟环境里,不会污染全局。
注意:poetry 的依赖解析速度比较慢,尤其是项目依赖很多的时候。我第一次用 poetry 装一个包含 50+ 依赖的项目,等了快两分钟。不过,慢是慢了点,但它给出的依赖组合是经过 SAT 求解器验证的,基本不会出现冲突。
3.4 三者的选择策略
说了这么多,到底该用哪个?我画了一张图,帮你快速决策:
说白了,我的个人经验是这样的:
- 做深度学习实验:用 conda 创建环境,装 PyTorch/TensorFlow 和 CUDA 相关的东西。这些底层依赖用 conda 装最省心。
- 写一个可复现的项目:在 conda 环境里,再用 poetry 管理项目依赖。poetry 的 lock 文件能保证「换台机器也能装出一模一样的环境」。
- 快速验证一个想法:直接用 pip,简单粗暴。反正跑完就删,不纠结。
我的工作流:conda create -n myproject python=3.9 → conda activate myproject → poetry init → poetry add torch numpy ... → poetry install。这样既享受了 conda 的环境隔离和二进制包支持,又享受了 poetry 的依赖锁定。两全其美。
3.5 避坑指南
最后,分享几个我踩过的坑,你遇到了能少走弯路:
- 不要混用 pip 和 conda 装同一个包:如果你用 conda 装了 numpy,又用 pip 装了一次,可能会覆盖掉 conda 的版本,导致依赖链断裂。我建议:能用 conda 装的,优先用 conda;conda 没有的,再用 pip。
- poetry 的 lock 文件要提交到 Git:很多新手把
poetry.lock加到.gitignore里,这是大忌。没有 lock 文件,别人拉下来项目,装出来的依赖版本可能跟你不一样。 - conda 的 channel 优先级要小心:默认的 conda 仓库包更新慢,很多人会加 conda-forge。但 channel 的优先级会影响包的版本选择。我习惯把 conda-forge 放在最前面:
conda config --add channels conda-forge。 - pip 的 --user 参数慎用:这个参数会把包装到用户目录下,而不是虚拟环境里。我见过有人用
pip install --user torch,结果全局环境被污染,其他项目也跟着遭殃。
嗯,包管理器这块,说复杂也复杂,说简单也简单。核心就一句话:根据项目场景选工具,别一个工具打天下。你想想看,用螺丝刀去拧螺母,不是不行,但效率肯定低。选对了工具,后面的事就顺了。