ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python虚拟环境全指南:从venv到uv,彻底解决依赖冲突

Python虚拟环境全指南:从venv到uv,彻底解决依赖冲突 刚接手公司那台旧服务器的时候我差点被一团乱麻的Python环境搞崩溃。队里几个人各写各的脚本有人用Django 2.2有人项目里非要Django 4还有一个量化小组在跑pandas和numpy的老版本组合。当时谁要装个新包直接在全局pip install结果今天升级了某个依赖明天另一个脚本就报ImportError。后来我花了整整一个周末把所有项目按虚拟环境拆开从此再没为“环境打架”的事情半夜起来修过。这篇内容不是照搬官方文档而是结合我自己的使用习惯把Python虚拟环境从原理到创建、从编辑器接入到项目迁移、再到绕坑经验一次性讲清楚。不管你是刚入门的小白还是被依赖问题折磨过的老开发按着下面的节奏走基本能把“创建虚拟环境”这件事彻底拿捏住。1. 为什么每个 Python 项目都应该有自己的独立“运行房间”很多人第一次接触虚拟环境最直接的疑问是我明明可以用pip把包装到系统里为什么非要搞出一个“隔离空间”回答这个问题最好的方式不是讲定义而是讲一次我真实遇到过的依赖事故。1.1 一次依赖冲突事故我的 Django 教训去年我要维护一个老项目Django版本被锁在2.2因为里面有个第三方管理后台插件只兼容这个区间。后来同事新开了个接口服务需要Django 4.1的新特性。如果两套代码共用同一个全局site-packagespip在安装Django 4.1的时候会直接卸载掉2.2老项目的urls.py马上开始报错。哪怕你用pip install django2.2强行装回去新项目又启动不起来了。你想在两个版本之间来回横跳结果就是无限循环。这种问题在依赖稍微多一点的现实项目里几乎是必然发生的。不是只有Django才会这样TensorFlow和PyTorch、requests和httpx、Pillow和opencv只要版本敏感就会出现相似的情况。虚拟环境的价值在于每个项目拥有独立目录互相看不见切换项目就切换环境彻底把“全局公共区”的共享问题变成“项目自治”。1.2 虚拟环境的本质目录隔离与解释器重定向从技术底子上看Python虚拟环境做的事情并不复杂。你在某个目录下执行python -m venv .venv后这个目录里会出现binWindows下是Scripts、lib、include等结构。核心思路是创建一个“局部Python运行副本”里面有一份指向基础解释器的链接以及一个空的site-packages目录。当你激活这个环境之后环境变量PATH会被调整让.venv/bin排在最前面那么你在命令行里敲python或者pip实际拿到的就是虚拟环境里的解释器而不是系统全局的。这里有个容易误解的地方虚拟环境并不重新编译Python解释器它是对基础解释器的引用。但site-packages目录是全新的所以包装了哪些、装了什么版本各个环境互不干扰。简单类比一下全局环境就像一个大办公室大家的工位和抽屉混在一起谁动了公共区域都会影响所有人虚拟环境则是给每个项目单独开了一间带锁的工位你在自己桌子上摆什么都不会打扰别人离开时锁上门就行。1.3 虚拟环境能解决的问题清理、迁移、多人协作我整理过虚拟环境在日常开发里的几个核心收益选型时可以直接对照依赖隔离每个项目锁定自己的包版本不会互相覆盖也不会影响系统自带的Python。清理方便环境就是一个文件夹不要了直接删掉不污染系统。比起全局pip装乱了再逐个卸载省心太多。迁移可复现通过pip freeze导出依赖清单到新机器上执行一次安装几十秒钟就能还原出一样的运行环境。权限安全在公司机器上如果没有root权限全局安装经常碰壁虚拟环境安装在用户目录完全绕开权限限制。多人协作团队提交requirements.txt每个人用虚拟环境拉到同一组依赖版本减少了“在我电脑上明明能跑”的争议。2. 工具选型venv、conda 与 uv 该怎么选创建虚拟环境不是只有一条路。早期用virtualenv后来Python官方把venv装进了标准库做科学计算的人习惯用conda最近又冒出个速度惊人的uv。这几个工具各有自己的适用场景选错了不是不能干活而是会在后续维护时多绕弯子。2.1 venv不装额外依赖的第一选择venv是Python 3.3以后自带的标准库模块它的优势可以用一句话总结只要你的电脑能跑Python就能直接创建环境不需要再安装任何东西。对于大多数Web项目、脚本工具、一般的自动化任务venv完全够用。它的缺点是隔离的是Python包如果你需要同时管理多个Python版本比如一个项目要3.8、另一个要3.11单靠venv不够灵活因为它默认只能基于当前的解释器创建环境。我的习惯是只要没有特殊条件优先使用venv。原因很简单少依赖一个工具就少一层维护成本而且它在Windows、macOS、Linux上的行为已经打磨得很稳定。2.2 conda/anaconda应对科学计算与多版本 Pythonconda跟venv不是一个层面的东西。它本身是Anaconda发行版里自带的包管理器不仅能创建Python虚拟环境还能管理Python解释器版本甚至能安装非Python的二进制库比如CUDA相关的驱动依赖还有不少C扩展库。conda create -n py311 python3.11这种命令可以直接拉一个新版本的Python解释器出来这是venv做不到的。如果你搞数据分析、机器学习或者需要在同一台机器上给不同项目提供不同Python版本conda会是更省心的选择。代价是Anaconda整体比较庞大安装包动辄几GB而且conda的依赖解析速度明显比pip慢。现在很多人会用miniconda而不是anaconda来减负只保留conda核心装包再按需进行。2.3 uv用“快”解决虚拟环境体验问题的后起之秀uv是最近两年热度很高的Python包管理工具用Rust写的核心卖点就是“快”。我第一次跑uv venv的时候体感几乎是瞬间完成比原本python -m venv还要轻快不少。它不光能创建虚拟环境还能替代pip安装依赖甚至能解析版本依赖关系把整个工作流统一起来。对于新项目我现在的倾向是直接上uv。尤其配合uv sync这类命令根据pyproject.toml一键安装所有依赖并锁定版本体验非常接近现代语言的标准包管理器。不过要留意一点uv工作流比较新如果你的团队还在用老一套的requirements.txt直接切换可能带来学习成本这时候先用venv过渡也是一种理性选择。下表是我在项目选型时常用的对比方向直接判断即可对比维度venvcondauv安装成本Python自带需装Anaconda/miniconda单文件安装是否支持多Python版本不支持支持支持依赖安装工具pipconda pipuv pip管理适用场景通用项目科学计算/数据分析新项目/追求效率创建环境速度中慢快社区成熟度非常高高快速增长中3. 创建虚拟环境实操三种方式我都跑了一遍理论说再多不如直接把命令跑一遍。这个部分我按venv、conda、uv三种方式分别给出可复制的步骤并标注了Windows与Linux/macOS的差别。如果你只想要一个答案就直接跳到3.1先解决当前问题后面再探索其他工具。3.1 venv 创建与激活的完整命令第一步先确认Python版本。打开终端执行python --version我建议Python版本在3.8以上再用venv太低的话标准库的venv模块在某些场景下会有兼容问题。确认没问题后进入你的项目目录创建虚拟环境python -m venv .venv.venv是虚拟环境目录的名字你完全可以叫venv或者env不过业界习惯用.venv因为点开头的目录在文件管理器里默认隐藏视觉上不会让项目根目录显得太乱而且在VSCode等编辑器里也更容易被自动识别。创建之后下一步是激活环境。在类Unix系统Linux/macOS上source .venv/bin/activate在Windows的cmd里.venv\Scripts\activate.bat在Windows的PowerShell里.venv\Scripts\Activate.ps1如果你用PowerShell执行激活脚本时报错说“在此系统上禁止运行脚本”那是因为Windows默认的执行策略限制。可以用管理员权限打开PowerShell执行一次Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser设置完之后重新打开终端再激活即可。激活成功的标志是命令行的提示符前面多了(.venv)像这样(.venv) userhost:~$此时你再运行下面这条命令which python看到的路径应该是项目目录下.venv/bin/python这就说明你已经在虚拟环境里了。然后就可以安心用pip安装依赖pip install requests pip install django4.1.7需要退出环境时执行deactivate3.2 conda 创建虚拟环境以及常见参数如果你用的是conda第一步不是创建环境而是先想好要给这个环境指定什么Python版本。这样做最大的好处是不同项目可以完全独立使用不同的解释器不用为了某个老项目把全局Python改成旧版。我常用的创建命令是conda create -n alice python3.10 -y这里的-n alice是给环境命名为alice你可以换成项目名比如spider、django-web都行。python3.10是要求conda解析出一个3.10版本的Python-y表示遇到确认提示自动选yes免得手动回车。创建好后激活conda activate aliceWindows下如果在Anaconda Prompt里操作命令一样。激活之后命令行提示符会带上(alice)。这时候你再执行python -V可以看到当前环境指向的是刚创建的Python版本。conda还有一个很好用的能力环境列表查看。想知道自己创建过哪些环境直接运行conda env list输出里会同时显示环境名和对应的目录路径。如果你希望创建环境的同时把常用科学计算包也装上可以一步到位conda create -n ml python3.10 numpy pandas jupyter -y这样环境创建完numpy、pandas和jupyter都已经可用了省得后面再逐个装。缺点是conda解析这种综合命令时会比较慢可能要一两分钟属于正常现象。3.3 uv 快速创建虚拟环境与切换uv的用法对熟悉现代包管理器的人来说非常友好。先安装uvmacOS或Linux可以用系统的包管理器Windows上我一般用pippip install uv或者你也可以直接下载官方提供的可执行文件。安装完成后创建虚拟环境uv venv .venv --python 3.11--python参数可以省略省略时会用当前默认的Python版本。创建的速度非常快几乎不会感受到等待。激活方式跟venv基本一样。激活后你可以直接用uv pip替代pip来安装依赖uv pip install django我特别想提一下uv的“环境切换”体验。当你维护多个项目、每个项目都有独立环境时传统方式需要挨个激活、退出容易搞混。uv的思路是结合pyproject.toml每个项目根部放一个配置文件进入目录后执行uv sync它会自动根据配置创建好环境、装好依赖你不用关心环境具体叫什么名字。这种“进入目录即环境就绪”的方式省掉了大量心智负担也是越来越多人喜欢在切换项目时用uv的原因。4. 把虚拟环境接进 VSCode 与 Jupyter避免“解释器不对”的困扰很多人在命令行里能把虚拟环境玩明白一回到编辑器就迷糊了。最常见的问题是明明已经激活了环境VSCode的终端里也显示着(.venv)可点击运行脚本时用的还是全局Python或者是环境中根本没有的那个包。这背后十有八九是“解释器没有正确选择”。4.1 VSCode 选择解释器与终端激活的联动在VSCode里打开项目文件夹后按下CtrlShiftP输入“Python: Select Interpreter”回车。这时会弹出一个列表里面包含VSCode扫描到的所有Python解释器。你要选择带有.venv标记的那个路径通常长这样./.venv/bin/python选中之后VSCode右下角的状态栏会显示当前解释器路径。这里会出现一个非常有意思的现象即使你不在终端里手动激活环境VSCode运行Python脚本时也会使用这个解释器因为编辑器是通过解释器路径直接调用Python而不是依赖终端的PATH。但如果你打开VSCode的内置终端还希望终端里也激活环境有一种做法是依赖VSCode的“Python: Select Interpreter”联动机制当你选择了.venv/bin/python之后VSCode会自动在新建终端时激活对应的环境。实测下来这个功能默认是开启的个别版本可能会失效。失效时你可以在.vscode/settings.json里加一条{ python.terminal.activateEnvironment: true }如果你发现终端里没有自动激活也不要在意太多只要解释器选对了脚本运行就没有问题。开发时在命令行少敲几次activate会舒服很多。4.2 Jupyter notebook 使用虚拟环境内核Jupyter notebook的虚拟环境配置坑比VSCode更多。因为notebook内核默认跟Python环境绑定你在notebook里执行代码时用的解释器取决于内核选择的路径而不是当前终端激活的环境。正确做法是先激活虚拟环境然后在环境内安装ipykernelsource .venv/bin/activate pip install ipykernel然后把当前环境注册成Jupyter的一个内核python -m ipykernel install --user --name myenv --display-name Python (myenv)这行命令有两个参数需要注意--name是内核的内部标识必须唯一--display-name是Jupyter界面下拉列表里显示的名字你可以写成容易识别的名称。注册完成后启动Jupyterjupyter notebook新建notebook时在“Python”下拉菜单里选中刚才添加的“Python (myenv)”执行代码时使用的就是虚拟环境里的解释器和依赖了。如果你启动notebook后发现下拉菜单里没有你的环境很大概率是ipykernel没装进虚拟环境或者注册时用了root权限导致不一致。重新走一遍上面的步骤同时在安装时不要带--user除非遇到权限报错基本能解决。5. 虚拟环境迁移换电脑、换服务器时的实操流程虚拟环境本身不应该被直接拷贝着用。很多新人会想着“我直接把.venv整个压缩包发到新机器上不就行了吗”实际操作后就会遇到各种奇怪问题——新机器上包路径不对、二进制库不兼容、依赖丢失。正确做法是生成依赖清单在新环境里重建。5.1 requirements.txt 与 freeze 快照pip freeze是Python生态环境里最基础也是最重要的一项技能。在虚拟环境激活状态下执行pip freeze requirements.txt这个命令把所有已安装的包和精确版本号写进requirements.txt比如Django4.1.7、requests2.31.0。到了新机器上创建虚拟环境后执行pip install -r requirements.txt依赖就会按清单逐个安装。不过这里我要给一个更稳妥的建议用pip freeze导出时里面往往会混入一些传递依赖就是那些你并没有直接安装、只是因为其他包才被带进来的库。环境多了之后这类直接依赖和间接依赖容易混在一起。我更推荐在项目里单独维护一个requirements.in文件记录直接依赖然后通过pip-compile工具生成requirements.txt。但对一般项目来说先用freeze把环境跑起来完全没有问题。5.2 conda 环境导出和跨平台注意事项conda环境迁移有自己的一套命令。在源机器上执行conda env export environment.yml这个YAML文件会记录环境内的所有conda包、pip依赖以及下载渠道。新机器上恢复conda env create -f environment.yml如果只是跨Linux服务器的迁移这种方式的成功率很高。但如果你在Windows上创建conda环境然后试图在Linux上恢复会碰到很多平台相关的二进制包问题。跨系统迁移的时候最稳妥的方案是只迁移requirements.txt重新用conda建一个新的干净环境再安装依赖。5.3 复制环境时的绝对路径坑有一类问题经常发生在“直接拷贝.venv”模式里activate脚本内部有一个VIRTUAL_ENV变量记录的是环境创建时的绝对路径。当你把整个目录移动到别的位置后激活脚本会找不到原来的路径甚至提示No such file or directory。如果实在要移动最简单的方法是删除旧的虚拟环境在新位置重新创建然后执行pip install -r requirements.txt。对生产环境来说一定要把环境当成“可重建”资源而不是“可搬运”资源。数据可以备份代码可以备份环境永远用清单来复现。6. 我遇到过的一些虚拟环境问题与排查记录虚拟环境本身不难但真跑到团队环境或者生产服务器上还是会遇到各种意料之外的问题。我把自己踩过的一些坑整理出来按照“现象—原因—解决办法”的方式写你遇到类似问题时可以按图索骥。6.1 anaconda 创建虚拟环境失败有段时间同事在Windows上用Anaconda执行conda create -n test python3.9屡次报错提示信息里有“CondaHTTPError”或者“ResolvePackageNotFound”。排查下来发现两个原因一是conda默认的官方源在主网络下访问很慢超时导致解析失败二是conda的缓存目录里有一个损坏的锁文件。解决办法分两步走。先清理缓存和锁conda clean --all -y然后配置一个镜像源。这里不展开细节你只需要在用户目录的.condarc文件里写上镜像地址再重试创建命令即可。如果重试还是失败可以换个环境名和Python版本试试排除是特定包版本的问题。6.2 已激活但是 pip 仍然装进全局有一个比想象中更常见的场景终端里明明显示(.venv)但执行pip install之后pip show显示的路径还是全局site-packages。原因通常是虚拟环境里没有安装独立的pip模块导致pip命令被系统全局的pip接管了。新版venv默认会自带pip但如果你创建时加了--without-pip参数或者系统PATH中有别名/软链接抢占了优先级就容易出现这个问题。处理方法是显式指定模块执行python -m pip install --upgrade pip使用python -m pip而不是直接敲pip能确保走的是当前Python解释器对应的pip。这个习惯我在任何环境里都坚持能少很多莫名其妙的问题。6.3 依赖下载慢或失败的一些临时处理项目需要的第三方包太大或者源响应慢只要不是涉及违规网络的行为都可以用正常的镜像源处理。比如临时指定一个镜像源安装pip install -i https://pypi.tuna.tsinghua.edu.cn/simple requests如果想长期生效可以在虚拟环境的pip.confLinux/macOS或者pip.iniWindows里配置index-url。配置完记得重启终端再检查。还有一种情况是某个包编译需要系统底层库比如pip install pandas在部分精简Linux系统上会因为没有gcc失败。这时候手动安装系统的编译工具后再重试不是虚拟环境本身的问题。6.4 删除与重建环境别让环境越用越脏环境用久了pip进进出出依赖关系会变得混乱。我建议定期做一次“清零重建”deactivate rm -rf .venv python -m venv .venv source .venv/bin/activate pip install -r requirements.txt整个过程不过几分钟但能解决大部分由依赖残留导致的不确定问题。尤其是当你觉得环境“怎么这么慢”、“偶尔报些奇怪的错误”时重建比手工排查更高效率。回到文章开头那个混乱的服务器现在每个项目都有自己的.venv目录新同事加入时只需要拉代码、创建环境、安装依赖整个过程不再依赖某个人“手动维护全局包”。工具可以选venv的轻量也可以选conda的完整还可以选uv的极速但底层逻辑都是一样的把Python项目从全局混乱中解放出来让依赖管理从“靠记忆”变成“靠清单”。对我而言这可能是Python工程化里最值得先做好的一件事。
返回列表