打开终端之后最踏实的一刻,就是看到 conda 命令正常回显。Python 开发干了几年,真正救过我多次的,不是哪个花哨框架,反而是这些看起来平平无奇的 conda 常用命令:create、activate、install、export、clean、config。它们解决的不只是“装包”这一个小问题,而是 Python 环境里最让人头疼的依赖混乱问题。如果你也被“这个项目要 Python 3.6,那个项目要 Python 3.10”折磨过,或者被“装了这个包之后,另一个项目突然起不来了”坑过,那 conda 这套命令就是为你准备的。
这篇文章是我整理的工作台笔记,不算教科书,也没有废话,每一组命令都标注了适用场景和注意事项。内容覆盖环境管理、包管理、频道配置、环境导出复现、问题排查,适合刚接触 conda 的新手,也适合已经用了 conda 一阵子、却总在依赖冲突边缘反复试探的同学。
1. 为什么先搞清楚 conda 的定位,后面命令才顺手
1.1 conda 不是“另一个 pip”,它是环境级管家
很多新手第一次用 conda 都会把conda install当成pip install的高配版,这个理解很容易出问题。pip 装的是 Python 包,它只解决一件事:把某个 Python 包下载并安装到当前 Python 环境里。而 conda 管的是整个软件环境,它不只装 Python 包,还管理底层的二进制依赖,比如 C 库、编译器运行时、OpenMP、CUDA 相关组件,甚至指定版本的 Python 解释器本身。
举个生活化例子。pip 相当于搬家公司,只负责把你买的家具搬进屋里;conda 则更像一个承包商,它能先帮你把房子的水电、管道、楼层结构都按图纸布局好,再把家具放进去,并且保证不同房间之间互不干扰。这个“互不干扰”就是 conda 环境隔离能力的核心。你可以在 conda 里建无数个独立环境,每个环境有自己的 Python 解释器、自己的包集合,切换环境就像换了台电脑。
当你在命令行里敲conda create -n myenv python=3.9时,conda 不只是装了 Python 3.9,它还会拉起一个完整的环境骨架,包括 pip、setuptools 这些基础组件,并且保证后续装进去的包都基于这套解释器和配套二进制依赖来运行。
1.2 到底什么时候用 conda、什么时候用 pip
这个问题是我被问过最多次的,也是实际操作中最容易踩雷的地方。我的经验可以浓缩成两句话:
- 系统级依赖、需要预编译二进制的、跨语言库的(比如涉及 C/C++ 编译链的包),优先用 conda。
- 项目里用到的纯 Python 包,或者 GitHub 上刚发布的、conda 还没收录的包,才用 pip。
很多数据科学和机器学习相关的包都带有较重的二进制依赖,这类包用 conda 安装,conda 会自动把配套的底层库一并处理好。如果你用 pip 去装同样的包,pip 经常只做表面安装,等到运行时报错,你才发现缺了一堆系统库,然后还得手动挨个补。
但我也要说一句公道话:conda 的包仓库更新速度通常没有 PyPI 快。某些新发布的包,conda 可能一周后才有收录,这时候用 pip 在 conda 环境里临时装一下是最务实的选择。conda 环境和 pip 并不冲突,只要记住“在一个环境内部,优先 conda,找不到再 pip”这个原则就够了。
2. 环境管理:这组命令每天都要用,必须刻进肌肉记忆
2.1 创建环境时,参数里藏着你没注意到的细节
创建一个新环境,基础命令很简单:
conda create -n myenv命令里的-n是--name的简写,后面跟环境名。但我实际使用中几乎不会这样裸建环境,因为不指定 Python 版本太容易留坑了。如果当前默认的 conda 基础环境是某个特定 Python 版本,新环境可能继承一个你并不想要的版本,后面装包、跑脚本的时候才会发现版本不对劲。所以我的习惯是创建时直接把 Python 版本钉死:
conda create -n myenv python=3.10这样 conda 会创建一个 Python 3.10 的环境,不会污染也不依赖别的环境。如果你想在新环境里顺手装一批包,也可以一次性列在后面:
conda create -n ai_study python=3.10 numpy pandas scikit-learn注意,如果后面列了包,conda 会进入依赖解析过程,这个过程会比较慢,甚至看起来像卡住了。通常面对需要几秒钟到几十秒的“Solving environment”,属于正常现象,别一看到它不动就急着 Ctrl+C。我以前就犯过这个错,中断之后环境目录还剩一半,最后还得手动清理。
创建环境还有一个常用参数是--clone,比如你想把现在的环境完整复制一份用于备份或测试:
conda create --clone myenv -n myenv_backup2.2 激活、切换和退出环境,别再被旧习惯带偏
激活环境,不同时期、不同系统上的命令稍有不同。现在主流 conda 版本的推荐写法是:
conda activate myenv退出当前环境:
conda deactivate如果你的 conda 版本比较旧,你可能会遇到source activate myenv这种老写法,也还兼容。但我建议你尽早升级 conda 并使用新写法。新写法最大的好处是跨平台统一,在 Windows 的 PowerShell 和 cmd 里同样生效,不必再记两套命令。
激活环境之后,命令行的提示符前面通常会出现(myenv),看到这个前缀你就知道自己现在在哪个环境里。这里有个非常典型的坑:忘记退出某个环境,直接进入一个项目目录开始装包。结果所有包都装在了上一个环境里,后面项目换个环境跑就缺依赖。我的办法是,在每个项目目录里通过一个符号或配置文件标记对应环境,或者在激活环境后先跑一句which python检查解释器路径,确认自己不在错误环境里。
查看当前所有环境用:
conda env list这个命令输出里,当前环境那一行会有星号标记,同时还会显示每个环境的绝对路径。如果我需要彻底删除一个用不上的环境:
conda env remove -n old_env删除之前我会习惯性地用conda env list再看一眼环境名。因为-n后面如果拼错环境名,conda 会报错而不是删错环境,这个设计还算安全。但如果你用了conda remove --name env --all,它会把该环境下所有包和环境配置一起清除,这一步不可逆,真要执行前最好想清楚。
2.3 查看环境内部包信息,是排查依赖问题的第一手证据
conda list是我在调试环境时用到频率最高的命令之一。不加参数,它罗列当前激活环境下的所有包:
conda list这个输出看起来简单,里面信息量其实很大。每一行包括包名、版本、构建通道和 build 字符串,能直接看出这个包是从哪个频道来的。比如输出里numpy 1.26.4 py310h...后面的py310表示这个包是针对 Python 3.10 构建的,就这一行就能帮我判断常见的一个问题:为什么某个包装不上,多半是当前 Python 版本和包的构建版本对不上。
如果想查看指定包的版本信息,可以配合 grep 过滤:
conda list | grep numpy这在 Windows 上可能会遇到管道识别的问题,但现代 PowerShell 基本都已经支持了。如果你想把当前环境里的包信息存成文本、留作记录:
conda list -e > requirements_conda.txt这条命令生成的文本适合 conda 自己来读。不过我坦白说,实际工作中我更常用的是后面会讲到的conda env export,因为导出的格式更完整。
3. 包管理:安装、更新和回退的完整姿势
3.1 搜索包时,你要找的不只是包名
还在凭记忆猜包名然后直接安装?有这个习惯的同学,建议先试试conda search:
conda search numpy输出会列出 conda 仓库里所有与 numpy 相关的包版本、构建号以及它们所属的频道。这个命令最大的价值不在于“找到 numpy”,而在于让你看到 numpy 有哪些版本、哪个版本适合你当前的 Python 版本。搜索结果的 build 字段里如果带有py310,那就能用;如果显示的版本很旧,说明你可能没有添加合适的频道,这个问题后面专门讲。
搜索完之后,安装命令本身并没有太多花样:
conda install numpy但有一点我反复强调:在非基础环境安装包之前,确认当前环境已经激活。因为conda install会安装到当前激活的环境。如果你压根没激活环境,命令会落在 base 环境上,时间一长 base 环境就变成了一锅粥。
如果想安装指定版本,就在包名后面接等号:
conda install numpy=1.21.4支持精确版本号,也支持模糊版本:
conda install "numpy>=1.20,<1.23"这里建议加引号,防止命令行把>和<当作重定向符。我自己就吃过这个亏,不带引号的时候 shell 给我创建了两个奇怪的文件,那条命令根本没执行成功。
3.2 更新包时,请先想清楚你要承担的风险
conda update是给包做升级的:
conda update numpy如果你想一次性升级环境里的所有包,可以用:
conda update --all但请特别留意:conda update --all在执行时可能顺带改变某些已经安装的包的版本来满足依赖关系。换句话说,你本来只想升级 numpy,结果它把手动安装的几个包也给升级了,升级之后某些代码可能跑不通。最典型的就是机器学习和科学计算工具,升级换版往往带来 API 变动,项目在旧版本上稳定运行,升级之后就开始报错。
所以我的建议是:如果项目正在稳定运行,不要轻易对整个环境执行conda update --all,更稳妥的做法是只更新你明确需要的包。如果一定要做大版本升级,先导出一份环境文件,或者用一个克隆环境先做测试,测试通过再对正式环境动手。
3.3 删除包、清理依赖,不要留下“半卸载”状态
删除一个包:
conda remove numpyconda 会自动判断哪些包是该环境独有且不再被依赖的,然后一起移除。但你可能会遇到一个现象:某些包即使被删掉了,一些配置文件和缓存还在。这不影响功能,但如果你是个喜欢干净环境的人,可以用:
conda clean --all这条命令会清理缓存、索引、临时下载文件,能省出不少磁盘空间。我见过有的开发者 conda 目录有 30GB 以上的缓存,跑完clean之后直降 10 多个GB。对机器重度使用的朋友,这个命令值得每周执行一次。
需要注意,在删除包之前先确认是否还需要它。conda remove numpy不会提示你“这个包正在被项目使用”。而且如果包是从 pip 安装的,conda 不一定能封装清除,尤其是在 conda 环境里装的 pip 包,只能用pip uninstall来处理。
4. 频道管理:安装慢、装不上的问题,大半出在这里
4.1 频道就是软件源,把它配置好了,安装速度天差地别
conda 下载包的来源叫 channel,翻译成“频道”或者“软件源”都行。默认情况下,conda 会从官方渠道拉取软件包,但网络状况好时它很快,网络状况差时它能让安装命令卡死到你想砸电脑。
查看当前配置了哪些频道:
conda config --show channels添加一个频道:
conda config --add channels 频道地址删除一个频道:
conda config --remove channels 频道地址conda config --add channels不是简单地增加,它会把频道添加到列表最前面,优先级最高。字符的顺序决定了 conda 解析依赖时的查找顺序。配置多个频道时,conda 会按照优先级从上到下寻找,如果有两个频道都提供同一个包,它会优先选用高级别的那个。
一开始我以为“多配几个频道”是好事,后来才发现这也可能带来麻烦。不同频道的同一个包可能因为构建方式不同,互相之间的依赖组合变复杂,甚至出现“包 A 在这个频道要有,包 B 在另一个频道要有,结果两个包之间二进制不兼容”的局面。所以我最终的做法是:配置一个主要的高质量频道,再加一个辅助频道,不到万不得已不继续叠加。
如果不想修改全局频道配置,还可以临时指定频道去安装:
conda install numpy -c 频道名称这一招很适合“我就想试一下这个包在这个频道的构建版本”的场景。
4.2 关于镜像源,你自己动手配过才知道水有多深
下载包太慢、经常中断,是很多人配置镜像源的初衷。但我想先提醒一句:镜像源的选择要考虑稳定性和更新频率,不要随便找一个小站点就配上,而且配置之前最好确认它支持 https。这个操作本身不复杂,只是需要你去对应的开源社区官网查找可靠的镜像地址,按官方说明添加即可。
配置完成之后,可以通过:
conda config --show-sources查看所有配置文件的位置。如果你不小心把某个频道弄得顺序不对,可以编辑配置文件,或者用conda config --remove-key channels恢复默认频道设置。这个命令很大胆,但它会清空你所有的频道配置,只留下默认值,算是一个“重置频道”的快速手段。
我自己的习惯是,配置好频道之后,第一次安装包之前先跑一条conda clean --index-cache,清掉旧的索引缓存,让 conda 重新拉取新频道索引。很多配置完频道却发现下载源没生效的人,卡就卡在缓存残留。
4.3 本地包安装和离线安装
如果你的环境不能联网,或者你手上只有别人拷贝来的安装包,那也会用到本地安装:
conda install 包文件名.tar.bz2也可以把本地包所在目录当作本地频道:
conda install -c 本地目录路径 包名这种安装方式在工作环境受限时特别实用,但要注意版本匹配,本地包的构建版本必须和当前环境的 Python 版本兼容,否则会报“packages not compatible”之类的错误。没联网的环境还有一个技巧:提前在能联网的机器上用conda list -e导出包列表,然后在离线机器上安装对应版本的包文件,保证一致性。
5. 环境导出与复现:让别人一台机器一分钟复刻你的环境
5.1 不同场景选不同的导出方式
环境复现大概是团队协作里最刚需的场景。我见过太多人把整个环境用conda list -e > requirements.txt导出来发给同事,结果同事一条条装,装了两天还在报错。真正该用的命令是:
conda env export > environment.yml导出的 YAML 文件里完整记录了环境名、依赖包、构建版本、频道信息。拿到这个文件的人,只要执行:
conda env create -f environment.yml就可以完全复刻一份环境。这里的-f是--file的简写,也可以写成:
conda env create --file environment.yml默认情况下,yaml 文件里带的环境名会直接用于创建环境。如果你不想用里面写的名字,可以在创建时手动覆盖:
conda env create -f environment.yml -n new_env_name有一点要提醒:conda env export导出的文件包含了很多具体的构建号,比如numpy=1.26.4=py310h...,这带来了很高的精确性,但也带来了脆弱性。跨平台时,同一版本在不同操作系统上可能没有相同的构建号,那同事在一台其他系统的机器上执行conda env create时会失败。
我的变通方案是:团队内部先约定统一操作系统环境。如果做不到统一系统,那就考虑用不带构建号、只带版本范围的导出方式。
5.2 记录核心依赖:从历史中导出干净清单
导出环境文件还有一种更“治本”的姿势:
conda env export --from-history这个命令导出的 YAML 只保留你显式安装过的包和 Python 版本,不会把环境里所有传递依赖的构建号都列进去。它的好处是简洁、可读性强、跨系统兼容性好。比如你当初只装了python=3.10、numpy、pandas,使用--from-history导出的文件就是这些核心项。这样在另一台机器上重建时,conda 可以自动解析合适的依赖版本,比逐条锁定构建号更容易成功。
当然,--from-history也有坏处:它本身不做版本锁定的记录,如果以后依赖变化了,原项目复现的效果就没那么精确。所以我通常在快速搭建原型、把项目分享给其他人的时候用--from-history,在发布正式成果、需要严格复现结果的时候用完整conda env export。两类场景分开处理。
5.3 pip 包该怎么办
实际项目中,你总会在 conda 环境里用 pip 装一些 conda 仓库里没有的包。conda env export导出的文件里会有pip:段落,自动把这些 pip 依赖也记录进去。这样生成的 YAML 文件是“双通道”的,拿到它的人执行conda env create时,conda 会先装 conda 包,再调用 pip 装上 pip 段落里列出的包。
这看起来很完美,但仍有一个隐患:pip 依赖那部分不会记录每个包的具体来源,如果某个包是从私有源装的,别人换了环境之后可能无法安装。如果是这种情况,建议手工编辑生成出来的 YAML,把私有源地址也写清楚,或者干脆把 pip 依赖做成一份独立的requirements.txt,分开交付。
5.4 环境导出之后的空间占用问题
你可能已经注意到,conda 环境创建多了之后磁盘占用非常吓人。每个环境都有自己完整的解释器和依赖库,几十个环境加起来,几十 GB 很正常。此时用conda env export备份环境就显得格外必要——因为很多环境不需要长期保留,导出文件之后,就可以放心清理旧环境,让新项目重新建环境。空间不足时,这个操作顺序能救急。
另外,conda clean --all可以说是所有 conda 命令里性价比最高的一个。清理之后不影响现有环境,只是把缓存和中间文件删掉。我通常一旦发现磁盘空间不足,会先跑一遍conda clean --all,再考虑删环境。
6. 常见问题与排查技巧实录
6.1 “Solving environment”卡死,多数时候不是电脑坏了
conda 安装或更新时长时间卡在Solving environment,是新手最容易慌的场景。实际上这是 conda 在解析依赖关系,它要把当前软件包目录里所有候选版本的二进制依赖关系进行匹配,是个计算密集的过程。
针对这个困扰,我总结了几条实用对策:
- 优先使用已配置的频道且不要配置太多频道,频道越少、解析速度越快。
- 尽量安装明确指定版本的包,比如
conda install numpy=1.26,这能帮解析器缩小搜索范围。 - 保持 conda 自身在较新版本,新版本对依赖解析算法有明显改进,具体可以通过
conda update conda升级。 - 如果解析始终不出结果,可以先按
Ctrl+C中止,然后执行conda clean --index-cache清理索引缓存,再重试。 - 如果当前环境里包特别多,解析一定比新环境慢,可以考虑先创建一个干净环境验证问题。
还有一个关于解析器的小技巧:如果你要装某个特别复杂的包组合,同时还想保住环境里其他包不变,可以在conda install时附带参数--freeze-installed。这个参数会约束 conda 不要随便改动已安装的包,只解析你新加入的包。代价是可能装不上某些需要连带升级的包,但对稳定项目来说,稳比新更重要。
6.2 环境目录被锁、命令报错“already exists”或“file lock”
有时上一个 conda 命令还没完全退出,你紧跟着又启动了一个新命令,可能会遇到环境锁错误。conda 会在环境目录里生成一个锁文件(.conda_lock),如果上次进程异常退出,锁文件残留,后续命令会一直报错。简单的处理方式是删掉该环境的锁文件,然后重试。但要先确认当前没有 conda 进程在写这个环境,否则删锁会更乱。
还有一个常见问题是创建环境时环境名和已有环境重名。conda create -n env2报EnvironmentNameNotFound或者提示already exists,前者通常是你想要进入的环境根本不存在,后者是你看错名字了。遇到这种情况,不要硬着头皮删环境,先用conda env list看清楚环境到底叫什么名字。命令行提示的报错信息不长,但它一般都会告诉你当前环境名列表,仔细读一遍,能省不少力气。
6.3 包版本冲突时报错满天飞,怎么读才有效
版本冲突是 conda 使用中最磨人的问题之一。报错信息往往很长,里面有package_a -> package_b -> package_c这样的依赖链条,看得人头皮发麻。
我建议先把报错信息分成三层读:第一层是最顶部的error那一段,它会告诉你哪一个包和哪一个包之间存在版本冲突;第二层是冲突链条里靠前的几个包,这通常是根因所在,链条长度本身不一定重要;第三层是报错末尾提到的“检查哪个环境的包列表”,它指引你去看冲突包所在的环境。
实际处理上,多数冲突有三个解决方向:一是给冲突的某个包指定版本,比如conda install package_a=1.2;二是调整频道优先级,或者换用社区频道重装;三是把环境重建成一个更干净的组合,不在一堆旧包上反复打补丁。如果该环境只是测试用途,重建环境比试图解决依赖传递要快得多。反正现在有了conda env export -f environment.yml,重建的成本已经被压得很低了。
6.4 conda 命令找不到或版本混乱
如果你在自己机器上装了多个 Python 发行版,或者系统里原本有 Python,又装了 conda,很容易出现conda: command not found。这通常意味着 conda 没有被正确写入 PATH,或者你正在用的终端不是启动 conda 的同一个 shell。解决办法是重新打开终端,或用下面这个标准命令来初始化当前 shell:
conda init然后重启终端。这个命令会修改 shell 配置文件,把 conda 初始化脚本写入其中。如果你用某些特殊 shell,conda init 也支持指定 shell 类型,比如conda init zsh或conda init powershell。
还有另一种情况:命令行里能认出 conda,但它指向的却是另一个环境里残留下来的旧版本。可以用which conda检查当前使用的是哪个 conda 可执行文件。如果发现进入了别的环境,先conda deactivate,再conda activate base回到基础环境。基础环境是 conda 自己所在的环境,它是整个 conda 系统的根。
6.5 下载包总中断或者速度极慢
这个问题有一部分确实出在网络环境上,解决思路不是撞运气,而是配置一个稳定的镜像源。具体地址需要去开源社区官网查最新信息,我这里不写具体站点。配置完成后,记得用上面提过的conda clean --index-cache清理缓存,然后重试。还有一些经验,比如一次性不要安装太多包,分段安装更容易成功;安装失败后不要重复点执行,先查看报错信息,因为 conda 已经下载好的部分会缓存,重试通常不会完全重头来过。
另外补充一个奇怪但真实的经验:有时安装超大包时,终端窗口突然失去响应,这不一定代表下载失败,可能只是某个依赖的下载过程特别长。给它一点时间,或者观察其他网络进程是否还在跑。急躁地按 Ctrl+C 反而留下半成品缓存,下次安装还得重新校验。
7. 实操心得:这些年我用 conda 攒下的几条土办法
最后聊几句经验,不算系统教学,更多是个人习惯。
第一个习惯:建环境时一定要指定 Python 版本,不要省这一步。省一时的手敲,后面可能换来一整天的调试。
第二个习惯:环境命名不要起test、env、new这种没辨识度的名字。我会用“项目名 + Python 主版本”的结构,比如recommend_py310。一个环境对应一个项目,长期用下来逻辑非常清晰。
第三个习惯:项目里固定放一份环境导出文件。无论是environment.yml还是requirements.txt,要和代码一起纳入版本管理。团队协作时,新人拿到代码第一件事就是建环境,环境文件质量直接决定他们今天的开工心情。
第四个习惯:用文件备份环境,而不是相信“我删了这个环境以后还能凭记忆重建”。人脑记不住几十个包的精确版本,但conda env export能记住。
第五个习惯:敢于清理。环境数量一旦超过 20 个,磁盘空间必然会报警。先导出、再清理、再按需重建,这一套流程能让你在空间紧张时游刃有余。
关于 conda 常用命令能说的也就这么多。如果你哪一天也被依赖问题折磨得想撞墙,回到终端里敲一句conda env list,看清自己身在哪里,再去处理手头的环境。大概率能救你一次。