ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python虚拟环境全解析:venv与conda的异同与选型指南

Python虚拟环境全解析:venv与conda的异同与选型指南 我先描述一个很多人应该都经历过的场面同一台机器上的全局Python环境既跑着一个Django老项目又装着数据分析用的pandas脚本还存了一个深度学习demo。某天你发现项目A要用的numpy版本被项目B的依赖偷偷升级了于是A开始报错你把numpy降回去B又崩了。最后只能把整个环境删掉重装一下午就这么没了。这种问题太典型根本原因就是所有项目的依赖都堆在同一个site-packages里彼此之间没有隔离。今天这篇总结围绕python -m venv和Anaconda/Miniconda这两条最主流的虚拟环境路线把它们的异同彻底梳理一遍。我会从底层机制、具体操作、常见坑、选型建议几个层面展开而不只是列一堆冷冰冰的命令。如果你刚开始接触虚拟环境、还在纠结到底用哪种方案或者已经被环境问题折腾过几次、想彻底弄明白原理这篇文章应该能给你一个比较完整的答案。1. 虚拟环境到底帮我们解决了什么1.1 全局环境是怎么一步步失控的Python的第三方包默认安装到当前解释器对应的site-packages目录。这个目录对同一解释器是全局共享的你装进去的每个包所有项目都能看到、也都能被影响。问题出在依赖的传递性pip install requests并不会只装requests本身它会把urllib3、certifi、charset_normalizer等一系列依赖一并装好或升级。如果项目B恰好锁定了urllib31.26而项目A的某个依赖把urllib3升到了2.x那项目B下次启动大概率直接报错。更麻烦的是这种冲突不是你注意到了就可以避免的。很多包在安装时并不会提示我顺手改了哪个依赖等你发现的时候环境已经被改得面目全非了。全局环境就像一间没有隔断的共用厨房每来一个项目就往里添调料最后谁也不确定锅里到底是什么味道。虚拟环境的核心思路很简单给每个项目一个独立的空间这个空间有自己的site-packages装包只影响当前空间删掉也互不牵连。1.2 虚拟环境做的事本质上只有三件不管用venv还是conda虚拟环境要成立都需要搞定三件事一个可用的Python解释器或者指向某个解释器的入口一个独立的第三方包安装目录也就是环境自己的site-packages一套切换机制让你在执行python、pip命令时系统找到的是当前环境里的解释器而不是全局的第三点通常通过激活脚本来实现。激活的本质是修改shell的PATH把当前环境的binLinux/macOS或ScriptsWindows目录放到最前面。这样你输入python或pip系统第一个找到的就是环境里的可执行文件。同理退出环境就是把这条路径从PATH里撤掉。明白了这三件事再去看venv和conda的差异很多困惑就能解开它们都在做隔离但各自的分工层次完全不同。1.3 两种工具两个不同的层次venv是Python标准库自带的模块它的定位是基于你指定的解释器做一个隔离层。它不负责帮你找Python你用Python 3.11创建的venv里面就是Python 3.11。conda的定位则大得多。它本身是一个包管理器加环境管理器不依赖系统里已有的Python甚至可以不装Python就运行。它管理的不只是Python包还包括Python解释器本身、非Python的二进制库比如CUDA、OpenSSL以及其他语言的运行时。这两者表面上都在做虚拟环境实际一个管的是进入项目后的那层壳另一个管的是整个运行时生态。下面把这层差异彻底展开。2. venv和conda的架构差异一个管包一个管整个生态2.1 venv的本质绑定指定解释器的隔离层执行python -m venv myenv之后系统会做这几件事在当前目录下创建myenv目录在myenv/binmacOS/Linux或myenv\ScriptsWindows下放入Python可执行文件、pip、activate脚本生成一个独立的lib/pythonX.Y/site-packages目录写入一份pyvenv.cfg记录这个环境基于哪个解释器创建注意venv不会从网上下载一个新Python也不会给你换个版本。它就是把当前指定的这个解释器复制一份壳Windows下通常是复制Linux/macOS下默认用符号链接想强制复制可以加--copies参数。所以如果你的系统Python是3.11那么用python -m venv创建的所有环境都只能是3.11。想用3.8你得先装一个Python 3.8的解释器再用python3.8 -m venv去创建。结论很清楚venv解决的是包与包之间的隔离它不解决Python版本管理的问题。2.2 conda的本质自带解释器的环境管理引擎conda和pip的最大区别在于conda是一个跨语言、跨平台的包管理工具它并不依赖系统里的任何Python。你装好Miniconda后conda自己就带着一个Python运行时和一套自动的环境管理逻辑。创建环境时用conda create -n py310 python3.10conda会去配置好的channel默认是repo.anaconda.com国内常换清华源拉取一个完整的Python 3.10作为这个新环境里的解释器。你可以在同一台机器上同时拥有Python 3.8、3.9、3.10、3.11的独立环境互不干扰。这是venv完全做不到的。conda还管理非Python的依赖。比如装PyTorch时通常需要配套的CUDA运行时conda可以通过同一个依赖树把cudatoolkit一并装好而pip很难做到这种跨组件的统一解析。这也是为什么数据科学和深度学习项目里conda的占比明显更高。conda安装的包也不是pip那种wheel格式而是从conda channel仓库下载的二进制包老格式是.tar.bz2新格式是.conda。安装时conda会走一个完整的依赖解析器把所有包的版本组合当作一个整体来求解选出大家能共存的组合。这个求解过程更严格也更慢但装完之后环境内部的兼容性通常更有保证。2.3 一个关键推论你需要先有Python还是conda就是Python用venv时你始终需要一个外部Python来启动一切。用conda时conda自己就是那个Python的提供者你不需要提前安装任何解释器。这就是两条路线在架构层面的分水岭。很多新人不理解为什么装了Anaconda还要再创建虚拟环境——因为Anaconda的base环境是一个默认给的地基你可以在上面盖很多个隔离的房间独立conda环境。base本身不应该变成杂物间而是保持干净、只放最基础的包。打个比方venv是给你一个空镜头筒让你把手头那颗镜头装进去conda则是一条完整的镜头生产线你告诉它要什么焦段的镜头它现造一颗给你还要保证这颗镜头能和你的机身兼容。3. 从创建到删除的完整操作对比3.1 创建环境时最大的习惯差异venv的创建非常项目化你进入项目的根目录然后python -m venv .venv.venv就是项目目录下的一个隐藏文件夹跟着项目走。.venv通常会被写进.gitignore不提交到版本库。conda的创建则是集中式管理conda create -n myenv python3.9这个myenv环境默认放在conda安装目录下的envs/myenv里。你可以在任意目录执行这个命令环境位置和你当前在哪儿没关系。如果你想把conda环境建到指定目录比如D盘用-p参数conda create -p D:/envs/py39 python3.9创建的目录本身就是环境。这个-p用法后面讲迁移时还会再提。创建venv时我没法指定版本只能受限于当前解释器创建conda环境时强烈建议显式写python3.x。不写的话conda会按默认规则拉一个当前最新的Python版本但当前最新两年后就是环境里的老版本显式写版本是让环境可复现的第一步。3.2 激活与退出Windows上的第一个坑venv的激活命令Windows命令提示符.venv\Scripts\activateWindows PowerShell.venv\Scripts\Activate.ps1macOS/Linuxsource .venv/bin/activate如果PowerShell报错因为在此系统上禁止运行脚本通常是执行策略没放开运行一次Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserconda的激活命令是统一的conda activate myenv但注意新装的conda可能还没初始化shell。Windows PowerShell下会提示conda命令不存在或者conda activate不被识别。解决方案是先执行一次conda init powershellmacOS/Linux则用conda init bash初始化之后重启终端conda activate才能正常工作。Linux上有些教程让你手动往~/.bashrc里写PATH其实现在用conda init更规范它会自动把conda的初始化代码挂到shell配置里。激活的本质都是改PATH。你可以验证一下激活前执行which pythonWindows是where python激活后再次执行路径应该已经变成环境目录里的解释了。退出环境时venv和conda也都是一个命令deactivate/conda deactivate。3.3 安装包的两种方式你用的到底是哪个pipvenv里安装包大多数教程会写pip install xxx。但为了不出幺蛾子我强烈建议在虚拟环境里一律使用python -m pip install xxx为什么要这样因为pip install执行的是系统PATH里找到的那个pip而这个pip不一定属于你当前激活的venv。用python -m pip可以确保你调用的是当前环境里的Python自带的pip模块装的包百分之百进当前环境的site-packages。尤其是机器上同时存在多个Python版本时裸pip经常导致我明明激活了环境包却装到别处去了。conda环境里安装包有两种方式conda install numpy pandas python3.10或者python -m pip install requests优先用conda install装基础依赖pip只用来装conda channel里没有的包。两者的混用问题我在第四章单独展开这里只需要记住一个原则不要在一个环境里让conda和pip反复竞争管理同一个包。3.4 查看环境与删除环境venv没有内置的列出所有环境命令因为环境就是你目录下的文件夹。想查看就ls -la。想删除就直接删目录rm -rf .venvconda则有一整套环境管理命令conda env list # 列出所有环境带星号的是当前激活的 conda env remove -n myenv # 删除名为myenv的环境 conda list # 列出当前环境里的所有包还有一个容易被忽略的命令conda env remove -p D:/envs/py39按路径删除的环境对于用-p创建的环境更直接。3.5 环境导出与复现团队协作的胜负手venv环境导出pip freeze requirements.txtconda环境导出conda env export environment.yml两者差异很大。pip freeze会把当前环境里所有pip装的包连同传递依赖全部打出来包含很多间接包而conda env export则更像一份完整的环境快照包含conda包、pip包、Python版本甚至会记录非Python的库。实际协作里我更推荐做顶层依赖的导出而不是全量快照conda env export --from-history environment.yml--from-history只记录你直接创建环境时指定的包不记录自动拉进来的依赖。这样换台机器或者换版本时解析空间更大不容易因为锁死了太细的版本导致全套安装失败。下面把核心操作整理成表格方便对照操作venvconda创建环境python -m venv .venvconda create -n myenv python3.9指定路径创建无跟着项目目录走conda create -p D:/envs/py39 python3.9激活Windows.venv\Scripts\activateconda activate myenv激活macOS/Linuxsource .venv/bin/activateconda activate myenv退出deactivateconda deactivate装包python -m pip install pkgconda install pkg查看包pip listconda list列出所有环境无标准命令看目录conda env list删除环境直接删除目录conda env remove -n myenv导出环境pip freeze requirements.txtconda env export environment.yml用文件重建pip install -r requirements.txtconda env create -f environment.yml4. 那些年我们一定会踩的坑路径、源、混合管理和假损坏4.1 conda环境迁移到D盘场景、方案和你真正需要关心的conda虚拟环境怎么迁移到D盘是搜索引擎里居高不下的问题。根因很现实Windows的C盘空间紧张而conda默认会把环境和包缓存都放在C盘用户目录下。首先明确一点conda的存储分两部分环境目录默认C:\Users\你的用户名\miniconda3\envs和软件包缓存目录默认C:\Users\你的用户名\miniconda3\pkgs。如果只想把今后新建的环境放到D盘不需要搬迁改配置文件里的两个字段即可。Linux/macOS配置文件是~/.condarcWindows是C:\Users\你的用户名\.condarc。加入envs_dirs: - D:/conda/envs pkgs_dirs: - D:/conda/pkgs保存后新建环境时会默认落到D:/conda/envs。但这不会影响已有的环境已经建在C盘的还是留在C盘。已有的环境想迁移到D盘常见有三种做法。第一种导出再重建最通用也最干净conda activate myenv conda env export --from-history environment.yml conda env remove -n myenv conda env create -f environment.yml -p D:/conda/envs/myenv注意环境yml里如果有一行prefix: C:\...建议先删掉然后用-p指定新路径避免重建时路径自动指向老位置。第二种用conda-pack打包迁移适合那种环境里包含很多编译好的二进制包、重建成本很高的情况conda install -c conda-forge conda-pack conda pack -n myenv -o myenv.tar.gz把压缩包拷到D盘解压进入解压目录后执行一次环境自带的conda-unpack脚本它会自动修正环境内所有指向旧路径的配置。之后直接source D:/conda_envs/myenv/bin/activateWindows对应Scripts\activate.bat就能用。这个方案尤其在离线服务器上很有用但打包解压后不要在原环境目录里再跑一次conda-pack否则路径会覆盖乱。第三种如果是刚装好conda还没建任何环境最简单粗暴的方案就是安装时直接把安装路径改成D盘。在Windows安装向导里选自定义路径比如装到D:\miniconda3后面所有环境天然都在D盘。Linux用安装脚本时在提问阶段输入你期望的安装目录即可。4.2 venv环境直接复制到其他电脑一个必踩的隐藏坑很多人图省事想直接把项目目录连带着.venv打个压缩包传到另一台机器上解压用。结果一激活python路径还是指向旧机器的绝对路径整个环境基本报废。原因是venv里的pyvenv.cfg、bin/activate脚本以及Scripts/下的各种入口脚本都记录了创建时的绝对路径。目录一挪地方内部链接全部失效还没有现成的修复工具。正确的做法是venv永远不迁移只迁移依赖清单。在旧环境里执行pip freeze requirements.txt新机器上创建新环境后pip install -r requirements.txt几十秒搞定还顺带保证两台机器的包版本一致。conda的conda env export之所以敢迁移是因为它生成的environment.yml更像一份构建清单重建时从头安装天然规避了路径写死的问题。4.3 国内环境下配置清华源装包速度立竿见影不管用的是Miniconda还是Anaconda国内网络环境下一个高优先级的操作就是换源。conda默认从repo.anaconda.com拉包速度往往让人崩溃。清华源已经做了完整镜像配置方式是在.condarc文件里写入channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ show_channel_urls: true写完后执行conda clean -i清除索引缓存再conda update conda确认新源生效。注意channel顺序是有讲究的conda-forge放最前面意味着默认优先从这个社区频道解析依赖适合数据科学用户如果追求稳定小版本main和free靠前更稳。pip同样可以换源一行命令就够pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple换源这件小事直接影响conda体验。很多人觉得conda create半天没反应十有八九就是卡在默认源上。4.4 在conda环境里混用pip的假损坏为什么环境看起来不对劲这是conda用户最容易踩的一个坑。比如你建了一个环境用conda install numpy1.21装了numpy。之后因为某个包只能用pip安装顺手又执行了pip install numpy1.24。这时你可能发现conda list里显示的numpy版本还是1.21但import numpy实际加载的已经是1.24。更糟的是之后再执行conda install scipyconda求解器会根据它记录的numpy1.21去分配依赖有可能把numpy重新压回1.21而你根本不知道是谁改的。问题根源在于conda和pip各有各的包管理记录机制两者互相不感知。conda不维护pip装进来的包pip也不理会conda的依赖树。看起来环境没坏实际已经变成了两层皮。我的建议很简单在conda环境里优先所有包都用conda安装只有当conda确实找不到某个包比如某个只在PyPI上发布的私有包时才用pip而且只用来装那种包装完不要再对同名包执行conda操作。任何时候都别在同一个环境里让两个管理器反复拉扯同一个包。4.5 Anaconda Navigator点了Launch没反应一次标准排查思路Navigator是Anaconda自带的图形界面很多人第一次接触Anaconda就是从Navigator开始的但点Launch没反应在Windows上极其常见。先别慌排查顺序从底层往上走打开命令行执行conda --version确认conda本身没坏。执行conda update anaconda-navigator很多启动异常是老版本和当前Python版本不兼容导致的。查看Navigator日志。日志一般在用户目录下的.anaconda/navigator/anaconda-navigator.log打开看最后几十行如果有网络超时类的报错基本就是网络无法正常访问anaconda.org需要检查系统的网络连通性、代理设置或防火墙。看看是不是端口冲突、显卡驱动导致渲染异常这类情况多见于老版本卡在启动动画。实际处理经验里网络原因占比最高。如果Navigator一直无法正常打开最直接的方案是绕过它Launch的本质就是启动Jupyter Notebook、Spyder这类工具完全可以用命令行直接操作。管理环境靠conda create/activate启动Jupyter一条命令jupyter notebook就搞定。把命令行用熟Navigator反而有点累赘。5. 到底什么情况用venv什么情况用conda5.1 一张选型矩阵表对号入座你的实际场景推荐方案理由只想隔离一个普通Web项目系统Python够用venv轻量零额外依赖几条命令完事日常脚本、工具包开发不需要多个Python版本venvPython官方自带跨机器通用性最好同一个电脑上要跑Python 3.8/3.9/3.10多个版本conda一个conda就能管理所有解释器版本深度学习、科学计算涉及PyTorch/CUDA/编译型依赖condaconda能统一管理非Python的二进制组件团队在统一版本矩阵上做自动化部署、CIcondaenvironment.yml可复现性比requirements.txt更高公司或项目已经有成熟的pipvenv规范venv跟着团队既有约定走别自己另起炉灶只是试试Python还没决定要不要深入venv官网装Python之后直接用不需要先理解conda的概念5.2 venv优先的三个典型场景第一纯Python项目依赖都在PyPI上有完善的wheel包。比如FastAPI、Django、Flask这类Web开发requirements.txt加venv已经足够。不需要装额外的工具链也不理解conda的channel、solver这些概念学习成本最低。第二机器上Python版本统一、团队没有多版本需求。公司内网服务器、教学环境这类场景保持简便是美德。第三你已经用conda管理了多个Python版本但某个具体项目想要更细粒度的隔离。这里有个很多人不知道的技巧conda环境和venv不是互斥的。你完全可以先conda create -n py310 python3.10然后再用这个环境的python创建venvconda activate py310 python -m venv /path/to/project/.venv此时.venv里的Python就是3.10包隔离由venv负责而解释器版本由conda提供。两条路线组合使用环境管理能力直接拉满。5.3 conda优先的三个典型场景第一需要快速切换多个Python版本。conda create -n py38 python3.8和conda create -n py39 python3.39各建一个一条conda activate切换不需要手动下载安装多个解释器也不用管系统PATH里到底谁说了算。第二深度学习、科学计算项目的环境搭建。以PyTorch为例conda install pytorch torchvision torchaudio cudatoolkit -c pytorch这样一条命令能把Python包和CUDA运行时一起装好版本还是经过官方测试的匹配组合。pip在这种跨组件场景下的体验明显不如conda。第三你需要在多台机器上做高度一致的环境复现。conda env export --from-history environment.yml再加上conda env create -f可以把Python版本、conda包、pip包、非Python组件全部一次还原。5.4 Anaconda和Miniconda到底选哪个简单说Anaconda conda Python 几百个预装的数据科学包安装包有几个GBMiniconda conda Python 极少数基础包几十MB其他包按需安装。我的建议非常直接默认选择Miniconda。Anaconda那些预装包pandas、numpy、matplotlib、scikit-learn等确实方便但你的项目最终还是要独立建环境预装包在base环境里其实用不上几次。Miniconda的优势在于干净、可控装完先换个清华源需要哪个包再conda install哪个磁盘占用小base环境的干扰也少。如果你已经装了Anaconda想换成Miniconda思路也不复杂先导出重要的conda环境为environment.yml卸载Anaconda注意选择彻底卸载安装Miniconda然后逐个conda env create -f还原。环境里每个项目的包本身都不依赖Anaconda这个发行版迁移过程很平滑。最后再分享一个我用了很久的组合打法机器上装一个Minicondaconda负责管理所有Python解释器版本以及深度学习这类需要非Python二进制依赖的环境纯Python的普通项目直接从对应版本的conda解释器里再创建venv做项目级隔离。这样既享受了conda多版本管理的便利又保持了单项目的轻量两条路线的优势都用上了。如果你刚入门Python我的建议是小步走官网装个Python从python -m venv开始用起来不用一上来就背上conda一大套概念。等你哪天真的因为Python版本号不同、或者编译依赖问题开始头疼时再引入Miniconda也不迟——到那时你会发现环境管理这点事其实比很多教程讲得要简单得多。
返回列表