☰
Python虚拟环境实战:venv与conda选择、版本管理及迁移避坑指南
2026/10/27 3:51:58 网站建设 项目流程

干这行的朋友应该都有过这种经历:随手pip install labelme做图像标注,装完发现跑得好好的图像处理脚本突然报错,一查果然是依赖里的 numpy 被无声无息升级了。我前阵子刚帮同事排过这么一次,最后定位到就是因为它把包装进了全局环境,opencv、numpy、Pillow 的版本全被带飞,一个普通标注工具差点掀翻整个项目工程。从那以后,只要有人想往系统 Python 里直接叠依赖,我基本都会拦一下。

Python 虚拟环境就是用来治这种“环境污染”的,最常用的两套工具是 Python 官方自带的venv和数据科学圈很常见的conda,中间还夹着一个绕不开的问题:到底选哪个 Python 版本。三者组合起来,基本就是一个 Python 开发者日常环境管理的完整闭环。无论你是刚入门的新手,还是被环境问题折磨过几次的中级玩家,这篇内容都能给你一套可以直接抄作业的方案。

1. 虚拟环境到底治什么“病”:版本冲突的本质

初学者最容易踩的坑,就是把所有项目所需的三方库一股脑装进同一个 Python 环境。你想想,电脑上只有一个全局 Python,默认装包路径就是那个全局site-packages。项目 A 依赖numpy==1.24.3,项目 B 为了跑新版 torch 需要numpy>=2.x,两个项目共用同一个包目录,装完 A 再装 B,A 基本就瘫了。这就是典型的“共享污染”。

虚拟环境的思路很简单:给每个项目单独分配一套 Python 解释器配置和独立依赖目录,谁也碰不到谁。操作上,你通过venv或者conda create新建一个隔离环境后,再在这个环境里pip install,装进去的包只会落在该环境的site-packages里,而不是全局。环境切换后,import找到的是当前环境里的包,跟全局互不干扰。

理解到这里,你需要开始做一个选择:venv和conda到底用哪个?我个人的判断标准是看你要不要管 Python 版本本身,以及有没有很多非 Python 的底层依赖(比如 CUDA 相关的库、MKL、HDF5 这类 C/C++ 扩展)。venv只负责隔离依赖,不负责管理 Python 版本,conda则是把 Python 版本管理和依赖管理都包圆了。

维度venvconda
定位Python 官方自带,轻量隔离独立环境管理工具,附带包管理
Python 版本切换不支持,沿袭创建时的解释器创建环境时直接指定,多版本并行很自然
非 Python 依赖不处理能处理 C/C++ 库、CUDA toolkit 等
典型场景单项目快速隔离纯 Python 包数据科学、多版本并存、依赖较重的项目
体积小,几乎不占空间大,每个环境会复制一套核心运行时文件

注意:conda和venv不是二选一。很多资深开发者的做法是“用 conda 管 Python 版本,用 venv 管项目依赖”,这个组合我在第 5 部分会具体展开。

2. venv:官方自带的轻量方案,从创建到迁移

2.1 什么时候选 venv,什么时候劝你换 conda

如果你电脑上已经有一个稳定的 Python 3.9+ 解释器,项目又只是纯 Python 依赖(最多是一些有 wheel 的 C 扩展,比如 lxml、pyyaml),那venv完全够用。它没有额外软件负担,创建速度快,脚本逻辑透明,这也是很多基础教程推荐它的原因。

反过来,如果你的项目需要不同 Python 版本轮换测试,或者要装 PyTorch、TensorFlow、GDAL 这类依赖较重的库,venv就会有点力不从心,因为它管不了 Python 解释器版本。这时候用conda建一个python=3.11的环境,会比你自己去官网下三个 Python 安装包互切舒服太多。

2.2 venv 实操:五分钟创建一个干净环境

我的常规操作是在项目目录下建一个.venv文件夹,这样 IDE 能自动识别,也不会污染目录结构。命令非常简单:

# 用当前 Python 创建虚拟环境 cd D:\projects\demo python -m venv .venv

创建之后,Windows 下激活命令是:

.venv\Scripts\activate

Linux/macOS 则是:

source .venv/bin/activate

激活成功的标志是命令行前出现(.venv)前缀。这时候你再执行python,指向的就是虚拟环境里的解释器,装包也会自动进入.venv\Lib\site-packages。退出环境用deactivate,干净利落。

这里有个细节值得多说一句:很多新手在 Windows 的 PowerShell 下激活 venv 会碰到“无法加载文件,因为在此系统上禁止运行脚本”的红色报错。原因是 PowerShell 执行策略默认是 Restricted,解决方法是用管理员权限执行一行命令:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

设置后重新打开终端,就能正常 source 脚本了。

2.3 requirements.txt 备份与 venv 迁移坑

环境跑通后,第一件事就是导出依赖清单。这一步看似简单,但里面有个坑:直接pip freeze > requirements.txt会把环境中所有通过间接依赖装上来的包也一并导出,文件可能非常乱。更可控的做法是在项目里只维护顶层依赖,或者使用pipreqs扫描项目实际用到的库:

pip freeze > requirements.txt # 或者 pip install pipreqs pipreqs . --force

但venv最坑的一点是:它不能直接跨机器复制。虚拟环境内部的脚本里写死了创建时的 Python 绝对路径,你把整个.venv文件夹拷到另一台电脑,十有八九activate之后python路径还是指向旧的。我见过有人为了省事直接把环境文件夹打个压缩包传给别人,结果对方 activate 后import的还是全局包,排查了半天。

正确的迁移思路是:旧环境里导出requirements.txt,新电脑上重建环境,再安装依赖:

python -m venv .venv .venv\Scripts\activate pip install -r requirements.txt

这也说明:一个环境下迁移的正确依赖清单比环境本身更值钱。

3. conda:环境管理和 Python 版本切换的“重武器”

3.1 Anaconda 还是 Miniconda:别装一箱用不到的包

Anaconda 默认带了几百个数据科学常用包,安装包体积两三个 GB,对新手友好但也容易造成两个问题:一是很多包你根本用不到,白白占空间;二是预装版本往往会比较旧,和最新生态有偏差。我更推荐 Miniconda,它只内置 conda 和基础 Python,之后要什么装什么,环境瘦,迁移快。

安装完 Miniconda 后,我的第一步永远是配置镜像源,这一步对国内用户来说体验提升极其明显,默认源下载经常卡到怀疑人生。

3.2 创建 conda 环境与激活问题速修

创建环境时直接指定 Python 版本,这是 conda 比 venv 高级的地方:

conda create -n labelme_env python=3.11 -y conda activate labelme_env

激活后可以直接conda install labelme -c conda-forge,也可以pip install labelme,看包源。退出环境用:

conda deactivate

查看本机所有环境:

conda env list

有很多人都栽在安装完 conda 后,终端报“无法将‘conda’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,或者“condaerror: run 'conda init' before 'conda activate'”。前者的根因是 conda 的 Scripts 目录没进 PATH,最省事的修复不是手改环境变量,而是让 conda 自己初始化:

conda init cmd.exe # 或者 PowerShell 用户执行 conda init powershell

conda init的本质是往 shell 配置脚本里追加一段初始化逻辑,把 conda 的可执行目录加进 PATH,并定义 activate/deactivate 等命令。执行完一定记得重新打开终端。如果 PowerShell 下仍然报执行策略错误,同样先执行我上面提到的Set-ExecutionPolicy RemoteSigned -Scope CurrentUser。

注意:手改 PATH 虽然也能让conda命令识别,但会遇到 activate 时 “conda 函数不存在”的问题。所以优先用conda init,别自己硬拼路径。

3.3 镜像源配置:把下载慢的毛病一次解决

conda 默认访问国外官方仓库,很多用户装大一点的包时经常超时。解决办法是改~/.condarc文件,加入国内镜像源。以常见的清华源为例:

channels: - 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-forge 专属的包在国内大镜像源里更新可能滞后,遇到这种问题,可以在安装时临时指定-c conda-forge,走官方源单独拉。

pip 那边我同样会设置镜像源,一条命令搞定:

pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/

这行命令会把配置写进 pip 的 config 文件,之后所有pip install都默认走阿里云 PyPI 镜像。装包速度提升最直观,基本不用再等进度条转圈。

3.4 conda 环境迁移到 D 盘的两个靠谱办法

很多人发现默认情况下所有 conda 环境都被创建在 C 盘用户目录下,越装越大,C 盘空间告急。这里有两个靠谱的应对思路。

方案一:修改默认 envs 目录

如果你希望以后的新环境都安到 D 盘,直接配置 envs_dirs:

conda config --add envs_dirs D:\conda\envs

之后执行conda create -n 环境名 python=3.11,新环境就会创建在D:\conda\envs。已经存在于 C 盘的环境不受影响,但conda env list会把所有环境都列出来。

方案二:导出配置重建(推荐)

很多人问“conda 虚拟环境怎么迁移到 D 盘”,其实最稳妥的步骤是导出配置,再在 D 盘指定的路径里重建:

conda activate 旧环境名 conda env export > environment.yml

然后在新位置创建:

conda env create -f environment.yml -n 新环境名

这里要特别说明:conda env export导出的 yml 会包含prefix字段,指向源环境的绝对路径,重建时最好把那一行删掉或者改成目标路径。另外,如果环境里有通过 pip 装的包,yml 中会有一段- pip:依赖清单,重建时同样会自动安装。

我不太建议直接把 C 盘里的环境文件夹剪切到 D 盘。conda 环境内部大量的脚本、配置和二进制链接都记录了原始路径,直接挪窝容易出现“activate 成功但运行库加载失败”之类的玄学问题。导出重建虽然多花几分钟,但结果可控。

3.5 conda 与 pip 混用时最容易踩的坑

conda 环境里用 pip,最常见的问题是分不清 pip 指令到底指向哪里。很多人进入 conda 环境后直接pip install,结果发现包装到了全局 Python 里,因为当前环境里没装 pip,系统沿用了全局的 pip。

进入环境后先验证:

where pip

如果显示conda 环境目录\Scripts\pip.exe,才是环境内的 pip。如果显示的是全局路径,说明当前环境缺少 pip,先执行conda install pip,再继续装。

另一个规律是:能优先 conda 的包尽量用 conda 装,尤其是带 C 扩展或和底层库强相关的包(numpy、scipy、opencv),conda 能自动处理底层依赖;只有 conda 源里确实没有的纯 Python 包,再用 pip 补装。我见过有人反着来,在 conda 环境里用 pip 装了最新 numpy,之后 conda install 其他包时又把 numpy 回退到了旧版本,两边反复拉扯,最后环境直接坏掉。

4. Python 版本选择:不只看喜新,得看生态

4.1 为什么同一份代码在不同 Python 版本下表现不同

Python 版本差异带来的坑,最常见的是两类。

一类是语法差异。比如 3.8 版本里的walrus运算符:=,3.9 的字典合并运算符|,3.10 引入的match case模式匹配,3.12 对 f-string 表达式的增强。代码在 3.12 上写得爽,部署到 3.7 的环境上直接语法报错,根本走不到运行时排查环节。

另一类是依赖的二进制兼容性。很多带有 C 扩展的包在 PyPI 上提供的 wheel 文件是按 Python 版本区分的,比如numpy-xxx-cp312-win_amd64.whl只适用于 Python 3.12。如果你用了 3.13 但生态还没跟上,装包时只能现场编译源码,又慢又容易中坑。

所以版本选择本质上不是“越新越好”,而是“生态跟得上的版本才是好版本”。

4.2 新项目怎么选版本:一份实用的选择思路

我不太建议每个项目都跑去用最新版 Python,也不建议死守 3.8 这种“还能用”的老版本。通用的判断步骤是这样的:

  1. 先列项目的核心依赖,查这些库当前支持的 Python 版本范围。
  2. 看目标部署环境的运行时,比如云函数、服务器默认镜像是否已支持该版本。
  3. 没有历史包袱的新项目,建议选当前生态里已经被主流第三方库完整覆盖的版本,通常是 3.11/3.12 这一档,兼顾新特性和兼容性。
  4. 如果你要用机器学习框架,先查框架的官方支持矩阵,它们往往比 Python 官方慢半拍。

以当下时间点为参考,主流第三方库基本都完成了 Python 3.12 的适配,3.13 发布后也在逐步覆盖。保守选择 3.12,想提前体验新版本可以单独建环境试水,但别把它直接设成默认版本。

4.3 多版本并行:pyenv/conda 怎么搭

如果手头同时维护多个项目,有的必须用 3.9,有的用 3.11,核心诉求就是“一台机器上随时切换解释器”。这正好是 conda 的强项:

conda create -n py39 python=3.9 conda create -n py311 python=3.11 conda activate py39 # 切到 3.9 conda deactivate conda activate py311 # 切回 3.11

不想用 conda 的场景,Linux/macOS 下可以用pyenv管理 Python 版本,Windows 上有社区版pyenv-win。pyenv 负责切换解释器,venv负责隔离依赖,组合起来就是“版本由 pyenv 管,依赖由 venv 管”的模式。pyenv 提供的版本粒度更细,适合追求纯净环境的用户;conda 则胜在集成度高,装一个软件解决解释器加包管理两件事。

5. 最终组合拳:Miniconda + venv 的推荐工作流与常见问题速查

5.1 我自己在用的环境管理标准流程

这套流程我用了很久,核心思想就是让 conda 负责“选 Python 版本”,venv 负责“隔离具体依赖”:

  1. 安装 Miniconda,配置国内镜像源。
  2. 用 conda 建一个长期稳定的基础环境,比如python=3.12。
  3. 每次新项目,在项目目录里基于当前 conda 环境执行python -m venv .venv。
  4. 激活.venv后,只在该环境内用 pip 安装项目依赖。
  5. 维护一份requirements.txt,项目迁移时直接重建 venv。

这样做的好处是:conda 只需要管有限的几个 Python 版本环境,每个项目内的依赖绝不会互相污染,同时 conda 自身也不会因为频繁装包而膨胀臃肿。很多同事从“单 conda 环境手搓所有项目”改成这套流程后,环境报错率直线下降。

配合 IDE 使用,VSCode 里按Ctrl+Shift+P调出命令面板,输入 “Python: Select Interpreter”,直接选项目目录下的.venv;PyCharm 则在Settings -> Project -> Python Interpreter里指定。IDE 与你终端的激活环境不一致时,最容易出现“IDE 里能跑、终端跑不了”的怪象,这本质上是两个解释器指向不同环境,先检查这一点能省去大量排查时间。

5.2 常见问题速查表

现象可能原因解决办法
终端不认识 conda 命令conda Scripts 目录不在 PATH执行conda init cmd.exe或conda init powershell,重启终端
报 “run 'conda init' before 'conda activate'”只是 shell 没有初始化 conda 函数运行conda init 对应shell,重新打开终端
PowerShell 激活脚本被禁用执行策略限制Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
pip install 装到了全局当前环境未激活,或环境内无 pip确认 activate 状态,必要时conda install pip,用where pip验证
conda 创建环境下载超时默认源在外网,网络不稳修改.condarc走国内镜像源,执行conda clean -i
C 盘空间被 conda 环境撑爆默认 envs 目录在用户目录下配置envs_dirs指向 D 盘,并迁移重建必要时
venv 复制到另一台电脑没法用venv 绑定了创建时的绝对路径删掉 .venv,用 requirements.txt 重建
运行旧项目报 “NoneType has no attribute”装的依赖版本过新,库 API 变了锁版本重装,按项目实际版本建独立环境

5.3 环境管理里最容易忽略的几个细节

最后再啰嗦几句,都是我实际踩过坑之后才记住的:

第一,环境名和目录名要短。我见过有人给环境起名image_process_v3_final_final,每次 activate 输入都是一种折磨。短名字加注释文件比长环境名靠谱得多。

第二,不要在长期使用的环境里反复升级大版本。比如跑了好几个月的项目,某天突然conda upgrade numpy,可能顺手把很多依赖一起升级,直接引发连锁故障。要升级版本,优先在项目 venv 里操作,这样即使坏了也能靠删掉重装来救。

第三,requirements.txt 里尽量给关键依赖锁定版本号。写成numpy==1.26.4比numpy安全得多,至少能保证下次重建环境时行为一致。如果担心锁太死导致依赖冲突,可以用>=下界约束,但稳定性和可复现性优先的场景,我仍然建议精确锁定。

最后分享一个我习惯上比较受用的小技巧:每次新建环境后第一时间装ipykernel,这样在 Jupyter Notebook 或者 VSCode 的 Notebook 里也能直接选到这个环境作为内核,不用反复改 IDE 解释器。环境管理这件事,说到底就是在给未来的自己降低排障成本。宁可在开始多花五分钟,也别在半夜因为一个签名不符的包抓耳挠腮。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询