
讲个真事儿。
我们组有个实习生,入职第一天我给他布置了个任务:把项目跑起来。项目不复杂,就是一个Flask应用,依赖写在requirements.txt里。
他打开README,照着文档敲了四行命令:
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python app.py第一行就报错了。错误信息是No module named venv。我过去一看,他系统里的Python是3.5版本,venv模块在3.3就有了,不应该没有啊。
再一看,他用的不是系统Python,是Anaconda自带的Python。而Anaconda的Python,默认是没有venv这个模块的。
我帮他装了venv,跑通了项目。第二天,隔壁组的算法同事来找他,说有个模型需要Python 3.8环境(我们项目是3.9),让他帮忙跑一下。他心想,简单,换版本呗。结果venv根本不支持指定Python版本,它只能用创建环境时那个Python解释器。
两个小时后,他的电脑里已经装了四个版本的Python,三个虚拟环境工具,还有一堆乱七八糟的软链接。
那天我意识到一件事:虚拟环境这个东西,看起来是“环境隔离”,但venv和conda这两套工具,背后的逻辑完全不同。 用惯了其中一种的人,切换到另一种时,一定会踩坑。
在没有虚拟环境之前,Python世界是这样的:
你有一个全局的Python环境,所有包都装在一个地方。项目A需要requests==2.28,项目B需要requests==2.0。你装完A再装B,B会把A的依赖覆盖掉。A就挂了。
而且不同项目可能需要不同版本的Python本身。A用3.9,B用3.11。全局只有一个Python版本,怎么切换?
虚拟环境解决的就是这两个问题:
site-packages目录,装什么包互不影响但问题是,venv和conda对这两个问题的解法,走了两条完全不同的路。
venv是Python官方自带的虚拟环境工具。它的工作方式很简单:
当你执行python -m venv myenv时,它做了一件事:在myenv目录里复制一份当前Python解释器的副本。然后你激活这个环境时,实际上是调整了PATH环境变量,让命令行优先去myenv/bin里找python和pip。
关键点来了:venv里用的Python,就是你创建环境时系统里那个Python。你在Python 3.9下创建的环境,永远是3.9,无法切换到3.8。想换版本?重新创建一个环境。
# 用Python 3.9创建环境,永远只能跑3.9
python3.9 -m venv myenv
# 想用3.8?换一个解释器重新创建
python3.8 -m venv myenv38所以venv的隔离,是包级别的隔离,不是Python版本级别的隔离。它像一层薄薄的壳,只负责把当前项目的包和系统全局的包隔开。
因为轻量,venv用起来很直接:
# 创建
python -m venv .venv
# 激活(Linux/Mac)
source .venv/bin/activate
# 激活(Windows)
.venv\Scripts\activate
# 安装包
pip install requests
# 退出
deactivate优点:轻、快、简单、随Python自带,不需要额外安装。
缺点:不能管理多个Python版本;不同项目需要手动管理不同的环境目录;切换环境靠手动激活/退出,没有中心化的管理界面。
conda走的是另一条路。它不只是一个Python虚拟环境工具,它是一个通用包管理器和环境管理器,可以管理Python、R、Ruby、Lua等多种语言的包。
conda的环境是完全独立的。一个conda环境可以指定使用特定版本的Python,而且这个Python是conda自己下载和管理的,不依赖系统里装的Python。
# 创建一个Python 3.8的环境,名字叫py38
conda create -n py38 python=3.8
# 切换到py38环境
conda activate py38
# 创建一个Python 3.9的环境
conda create -n py39 python=3.9
# 切换
conda activate py39看到了吗?conda直接解决了Python版本切换的问题。每一个环境都是一个独立的小宇宙,里面有独立的Python解释器、独立的包、独立的目录结构。
conda的包也不只是Python包。你需要装一个C++编译器?conda install gcc。你需要装FFmpeg?conda install ffmpeg。这些都是conda管理的,不依赖系统包管理器。
优点:支持多版本Python;环境管理有中心化命令(conda env list);不只是Python包,还能管理系统级依赖;特别适合数据科学场景。
缺点:重。一个miniconda安装包就好几百MB,完全版Anaconda有几个GB。包安装速度有时比pip慢。某些包在conda源里没有,还得用pip去装。
我用一个比喻来帮你理解两者的本质区别:
venv像一个个独立的“容器”。每个容器里装的是一套特定版本的包,但容器本身是在一个固定的Python解释器上搭建的。你有很多个容器,它们各自装着不同的包,但底层用的Python版本都一样(或者你手动用不同版本的Python创建容器)。
conda像一个大“仓库”。仓库里有很多个货架,每个货架放着一套完整的环境——这个货架放着Python 3.8和它的包,那个货架放着Python 3.9和它的包。你从仓库里把一个货架整搬出来用,用完放回去,再搬另一个。每个货架都是完备的,自包含的,之间完全不干扰。
所以这两个工具在以下维度上完全不同:
维度 | venv | conda |
|---|---|---|
管理Python版本 | 否,只能使用创建时的解释器 | 是,每个环境可以指定版本 |
包来源 | PyPI(通过pip) | conda渠道 + PyPI(通过pip) |
环境存储位置 | 项目目录内(通常) | 统一目录(~/miniconda3/envs/) |
切换方式 | 激活/退出脚本 | conda activate/deactivate |
跨语言包管理 | 否 | 是 |
安装包大小 | 轻量(几十KB到几MB) | 重量级(上百MB到GB) |
适用场景 | Web开发、通用Python项目 | 数据科学、机器学习、多语言项目 |
你可能看过这样的文章:“conda和venv可以一起用,conda管环境,venv管包。”理论上可以,但实践中全是坑。
坑一:在conda环境里用venv
如果你在conda基础环境里创建venv,venv会复制conda的Python解释器。这个Python解释器的路径指向conda的目录,它的sys.path包含了conda的site-packages。结果就是,虽然你用了venv,但有些包还是会从conda里加载,造成莫名其妙的冲突。
坑二:在venv里用conda install
conda install不认识venv的环境,它只管把自己的包装到conda管理的目录里。你在venv激活状态下执行conda install,装是装上了,但venv根本找不到它。
坑三:混用pip和conda
这几乎是所有新手conda用户都会遇到的问题。conda环境里用pip装包,装了之后conda不知道,环境状态就不一致了。下次你用conda安装别的包时,conda可能会“自作主张”把pip装的包覆盖掉。反过来,pip也不知道conda装了什么,可能在安装新包时覆盖conda依赖的包,直接把环境干碎。
我见过最离谱的一次:一个同事在conda环境里用pip install了TensorFlow,然后conda install了一个依赖numpy的包,conda发现numpy版本不对,把numpy降级了。TensorFlow依赖高版本numpy,直接炸了。整个环境废掉,重新建了一个。
这个问题没有标准答案,但有几条判断标准:
强烈建议用venv的情况:
requirements.txt管理,配合Poetry或pip-tools强烈建议用conda的情况:
如果你非要用conda,又非要用pip,记住一条铁律:
conda list确认环境状态如果你不想在venv和conda之间纠结,还有一个更干净的选择:只用Poetry。
Poetry内置了虚拟环境管理(类似venv),同时解决了依赖解析(类似poetry.lock)和打包发布的问题。它不会帮你管理Python版本,但它会帮你管理项目的虚拟环境位置,以及所有依赖的版本锁定。
配合pyenv(专门管理Python版本的工具)一起用,可以组合出非常干净的工作流:
pyenv install 3.11.0
pyenv local 3.11.0
poetry init
poetry add requests
poetry shell这个组合的优点是每个工具只做一件事:
venv和conda没有谁更高级、谁更low,它们服务的对象不同。
选哪个,取决于你是什么类型的开发者,做什么类型的项目。
最后说一个实际建议:同一个项目里,只用一套虚拟环境方案。 要么全用venv(配合pip/poetry),要么全用conda。不要两个混着用,除非你愿意花时间弄清楚两种机制各自的边界在哪里。
而我那个实习生,后来我让他重装了系统。这次只装了Python官方版本加Poetry,再也没碰过conda。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。