
但凡写过几个正经 Python 项目的人早晚会遇到同一种糟心场景A 项目需要 requests 2.31B 项目因为老代码必须锁死 requests 2.25两个依赖一碰面直接把 Python 全局环境塞成了毛线团。装完 A 的依赖再跑 B要么报requests.exceptions.ConnectionError要么莫名其妙多出一堆版本错乱的包。这个问题靠的就是 Python 虚拟环境venv来解决——把每个项目的依赖装进独立的“抽屉”里互不干扰。今天这篇指南就是想把 venv 从创建、激活、依赖管理到常见报错、不同系统的坑一次性讲透不管是刚入门的小白还是写了好几年 Python 的老码农都能在里面找到能用得上的东西。1. 为什么需要虚拟环境依赖隔离的核心逻辑1.1 全局环境下的“套娃”困境很多人刚学 Python 时都是先装一个 Python然后开始pip install xxx全局安装。一开始很爽但是项目一多就开始乱了。我见过最典型的情况公司的 Python 2 项目需要 Django 1.11而新接的私活用 Django 3.2两个项目同时放在同一台电脑上全都指向同一个site-packages。你今天为了新项目装上 Django 3.2明天打开老项目直接ModuleNotFoundError老板问你怎么回事你只能憋屈地卸载重装反反复复。更深层的矛盾在于Python 的第三方库之间也存在版本依赖关系比如某些库要求依赖另一个库的最低版本装 A 的时候可能升级了 B结果 C 就崩了。全局环境就像一个共用厨房你原有的调料罐子随便动别人下一道菜就完了。为了解决这种依赖地狱虚拟环境应运而生。venv 的核心思想就是为每个项目创建一个完全独立的 Python 运行环境。这个环境有自己的site-packages目录自己的pip自己的 Python 解释器“入口”。在这个环境里装的包不会污染全局环境也不会被别的项目影响到。1.2 venv 的工作原理软链接、site-packages 与 PATH 隔离venv 到底做了什么用一句话解释它把“当前要用的 Python”和项目目录绑定在一起并通过修改命令行的 PATH 变量让python和pip这些命令优先指向虚拟环境里的可执行文件。我以 Linux/macOS 为例你执行python3 -m venv .venv后created 的目录结构大概是这样的.venv/ ├── bin/ # 包含 python, pip, activate 脚本 ├── include/ ├── lib/ │ └── pythonX.XX/ │ └── site-packages/ # 项目私有依赖 └── pyvenv.cfg # 指向基础 Python 的配置文件其中bin/python不是完整的一份 Python 解释器而是一个可以定位到基础 Python 安装路径的链接并在启动时优先把site-packages指向虚拟环境里的lib/pythonX.XX/site-packages。pyvenv.cfg里记录着home字段指向基础 Python 的系统目录。这样虚拟环境既避免了重新编译一份解释器又能做到依赖隔离。Windows 上结构略有不同但逻辑相通Scripts\python.exe、Scripts\pip.exe、Scripts\activate.bat以及Lib\site-packages。当你执行activate时系统会把D:\myproject\.venv\Scripts放到 PATH 的最前面于是你再敲python系统找到的就是虚拟环境里的解释器。这也解释了为什么 venv 文件夹被移动后经常报错——因为 pyvenv.cfg 记录的路径全变了链接就断了。1.3 venv 与 virtualenv、conda、pipenv 的选型对比很多新手会问有了 venv为什么还有 virtualenv、conda、pipenv直接说结论venv 是 Python 标准库自带的工具Python 3.3 之后就能直接python -m venv不需要额外安装但有些高级场景其他工具也有生存空间。我整理了一个对比表工具安装方式核心优势鸡肋之处venvPython 自带零依赖、轻量、够用只支持相同的 Python 版本不方便切换不同大版本virtualenvpip install virtualenv老牌工具兼容 Python 2功能与 venv 高度重叠如今已很少单独提它conda安装 Miniconda/Anaconda可以创建不同 Python 大版本环境管理非 Python 库如 C 库体积大、包解析慢项目迁移通常要写environment.ymlpipenvpip install --user pipenv整合 pip virtualenv Pipfile提供锁文件依赖解析有时候拖得很慢项目大了会卡从我个人的经验来说绝大多数 Python 项目尤其 Web 开发、爬虫、数据分析脚本用 venv 加 requirements.txt 就够了。只有在需要同时维护 Python 2.7 与 Python 3.11 环境、或者要安装依赖底层 C 库的时候我才会考虑 conda。pipenv 也不是不能用但如果你只是想快速隔离依赖明显 venv 的曲线最平缓。记住项目有多简单或复杂工具都应该为你的工作流服务而不是反过来。2. 创建与激活venv 的入门实操2.1 前提准备先检查 Python 版本与安装方式在创建 venv 之前你要先确认电脑上的 Python 装得对不对。我见过不少人装完 Python 后根本不知道装到了哪里直接在命令行敲python发现没什么反应更有倒霉的敲一下跳出了 Windows 应用商店的 Python 页面。这种情况先处理 Python 本体。Windows 上最简单的检查方法py --version python --version如果py --version有版本号说明你安装了 Python Launcher如果python --version没输出但py有输出试着用py -3或者py -3.11确认具体版本。Linux/macOS 上一般用python3 --version which python3如果你还在用python命令可能会踩到 macOS 自带 Python 版本过低的问题。建议先通过官网或包管理器安装一个较新的 Python 3并把python3加入 PATH。我已经数不清有多少次帮人排查 venv 问题最后发现他压根没装 Python 3只是电脑里残留着一个旧版本。2.2 在 Windows/macOS/Linux 上创建 venv 的命令与差异先给一套标准操作所有平台其实核心命令就一条但路径分隔符和激活方式有差异。我在 Windows 的项目目录下通常这样做cd D:\projects\myproject py -m venv .venvmacOS / Linux 则是cd ~/projects/myproject python3 -m venv .venv这里有两个关键点第一.venv带一个点是为了让文件夹在文件列表里看起来像隐藏目录而且很多 IDE 和.gitignore配置默认忽略它。第二使用python3而不是python因为某些 Linux 发行版里python指向 Python 2创建出来的是完全错误的环境。如果你创建完发现提示 “The virtual environment was not created successfully” 之类的报错通常是因为 ensurepip 没安装成功。只要不是 Python 安装本身残缺一般重装验证一下 Python 组件即可。Windows 上还有个坑如果你是通过 Microsoft Store 安装的 Python有时venv模块创建后会缺 pip这时候可以考虑直接用官网安装包安装并勾选 Add Python to PATH。2.3 激活、退出与检查当前环境创建好之后最重要的动作是激活环境。激活的本质是修改当前终端的 PATH。Windows 有两种常用终端命令.venv\Scripts\activate如果在 PowerShell 下遇到 “无法加载文件 ... because running scripts is disabled on this system”需要先执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser允许本地脚本运行。这个只影响当前用户的执行策略不算危险操作但你要是看到风险警告别慌这是允许你自己创建的脚本运行。macOS / Linux 下激活source .venv/bin/activate激活成功后命令行提示符前面会出现(.venv)这就是你判断是否激活的最直观标志。然后检查一下which python python -c import sys; print(sys.executable)如果sys.executable输出的是项目目录下.venv/bin/python或D:\projects\myproject\.venv\Scripts\python.exe就说明你已经在虚拟环境里了。我经常用这个命令来验证环境而不是只靠看提示符——因为有些 shell 会在激活后延迟刷新提示符或者你的 prompt 配置压根没显示虚拟环境名。需要退出虚拟环境时直接敲deactivate。在任何平台上这个命令都一致。如果你不激活其实也可以直接调用.venv/bin/python和.venv/bin/pip来操作但日常开发还是建议激活省心。2.4 给小白的一个叮嘱不要在 venv 里嵌套 venv这个听起来很蠢但我真见过有人在一个已经是虚拟环境的终端里执行了python -m venv .venv于是项目里出现了两层 venv随后 PATH 乱得离谱IDE 也找不到解释器。虚拟环境里再次创建虚拟环境并不会获得更高级的隔离只会让你自己怀疑人生。正确做法是如果你的终端提示符已经出现(.venv)就先deactivate再在项目根目录重新创建。另外也不建议把.venv放进另一个正在打包的虚拟环境目录里面用一个简单的约定一个项目目录只保留一个.venv且这个.venv是直接建在项目根目录下的。3. 依赖管理从 requirement.txt 到 pip freeze 的完整路径3.1 用 pip 安装包镜像与加速技巧虚拟环境里的 pip 和全局 pip 本质上还是同一个工具但默认会把包装到虚拟环境的 site-packages。你激活环境之后执行pip install requests软件包会落到.venv/lib/python3.11/site-packages/。国内网络环境下直接访问官方 PyPI 会慢得让人烦躁甚至经常超时。我个人的经验是稳定使用国内镜像比如清华源或阿里云源。命令举例如下pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple一条条命令写会比较累你可以直接把默认源配置到全局或当前用户配置中。在用户主目录下创建或编辑%APPDATA%\pip\pip.iniWindows或~/.pip/pip.confLinux/macOS写入[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple trusted-host pypi.tuna.tsinghua.edu.cn这样做之后所有pip install都会走镜像源速度提升相当明显。但要注意别把trusted-host写错否则会提示不受信任的警告。3.2 导出依赖清单pip freeze 的正确用法与坑一个项目做完一轮开发你最应该做的就是把当前虚拟环境里的依赖固化下来。标准命令是pip freeze requirements.txt你会得到一个像这样的文件requests2.31.0 certifi2024.7.4 idna3.7 charset-normalizer3.3.2 urllib32.2.1看到后面的精确版本没这就是冻结保证其他人或另一台机器安装时拿到一致的版本。但管他叫 “正确用法” 其实也有坑pip freeze会包含所有传递依赖也就是你直接安装requests时会自动装上的urllib3等项目并没有直接引用的包。在要求苛刻的场景里你更希望的是项目直接依赖清单而不是整个依赖树的快照。这时候可以试试pipreqspip install pipreqs pipreqs --encodingutf8 --force .pipreqs会扫描你的import语句生成最接近“项目真正引用”的 requirements.txt。但也要小心动态导入、可选依赖这类情况它可能漏掉。我通常的做法用pip freeze保存一份完整锁文件比如requirements-lock.txt用pipreqs生成一份干净的requirements.txt用于说明主要依赖。团队协作时前者保证可复现后者方便阅读。3.3 复现环境批量安装与版本锁定当你在另一台机器或让同事接手时只需要把 requirements.txt 放进项目目录然后激活新的虚拟环境执行pip install -r requirements.txt如果对方网络不太好加镜像源pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple到这里你想到了什么其实这就是 “依赖锁定” 的雏形。但说句实话pip freeze锁的是指定时间的完整环境而真实场景里依赖包会在恢复安装时继续解析依赖范围可能因为某个间接依赖发布了新版本而悄悄变化。所以有更高可复现要求的团队我建议用pip-tools这个方案pip install pip-tools pip-compile --output-filerequirements.txt requirements.in pip-sync requirements.txtpip-tools会先把依赖解析成一份锁文件再按照锁文件精确安装并移除多余包。这种手法在 CI/CD 里尤其管用。如果你目前的需求只是一个人写写脚本那pip freeze完全够用不必给自己加戏。3.4 在 VSCode 中切换解释器解决路径不对导致 traceback 的问题热词列表里有个特别真实的报错d:\pyth\.venv\scripts\python.exe d:\pyth\jb\20260923.py traceback (most recent call last)。如果你在 VSCode 里运行 Python 文件时遇到类似现象大概率是解释器选错了或者虚拟环境路径变化了。VSCode 默认的 Python 插件会从当前项目目录向上寻找.venv或其他虚拟环境。如果你之前用右下角的解释器选择器选过一个虚拟环境但后来这个.venv文件夹被删除或移动了插件仍然会存储那个旧路径一运行就弹出一堆 traceback。解决方案是在 VSCode 中打开命令面板CtrlShiftP/CmdShiftP输入 “Python: Select Interpreter”选择当前项目.venv里的python.exe或bin/python。如果你项目里确实没有.venv那就要回到终端重新创建并安装依赖。还有一个细节如果 VSCode 打开的“文件夹”不是项目根目录解释器选择也会迷路记得在 File Open Folder 里打开项目根目录。在settings.json里你也可以明确指定{ python.defaultInterpreterPath: ${workspaceFolder}/.venv/bin/python }但不用强行写这个除非你很确定团队所有人都会把 venv 放在同一路径。直接选择解释器比改配置文件更直观也免去了很多不必要的分歧。4. 进阶玩法venv 与项目的工程化实践4.1 把 venv 放进 .gitignore团队协作的必备操作很多人创建完 venv 后顺手git add .把整个.venv目录提交到版本库然后就被同事吐槽了。这确实是大忌.venv 体积大动辄几十到上百 MB而且里面装的是平台相关的二进制文件Windows 上和 macOS 上根本不一样提交上去不仅没意义还会频繁制造冲突。正确做法在项目根目录的.gitignore里加一行.venv/同时可以加__pycache__/、*.pyc等 Python 常规忽略项。团队协作时每个人拉代码后在自己的电脑上.venv创建一次虚拟环境再执行pip install -r requirements.txt完事。这看起来多一道手续但比起一份巨大的 venv 仓库不知道省了多少时间和麻烦。4.2 与 IDE/编辑器配合VSCode、PyCharm 的 Python 解释器设置除了 VSCodePyCharm 的使用频率也很高。PyCharm 里新建项目时可以直接选择 “New environment using Virtualenv”会自动帮你创建.venv并激活。如果是已有项目入口在File Settings Project Python Interpreter点齿轮选 “Add Interpreter” “Existing environment”找到你的.venv路径下的python.exe。选完后PyCharm 会根据这个解释器去解析项目里的依赖错误提示和自动补全都能对齐。这里提醒一下PyCharm 有时会自动为项目建一个名称为.venv的虚拟环境但默认 Python 版本可能不是你想用的那个。在创建项目时留意一下 Base interpreter 的路径和版本别选成/usr/bin/python3却不知道这是哪个版本。VSCode 的话我前面提过命令面板“Python: Select Interpreter”选择后可以打开一个 Python 文件状态栏右下角会显示当前解释器路径。任何时候发现状态栏里的解释器看起来不对都值得你停下来验证一下。4.3 自动化创建一键脚本与 Makefile 模板项目变多之后手动敲三行命令我都嫌烦。所以我通常会把环境创建过程写成一个可复用的脚本。这里给一份我常用的 Makefile 模板.PHONY: install run clean PYTHON ? python3 VENV_DIR ? .venv install: $(PYTHON) -m venv $(VENV_DIR) $(VENV_DIR)/bin/pip install --upgrade pip $(VENV_DIR)/bin/pip install -r requirements.txt run: $(VENV_DIR)/bin/python app.py clean: rm -rf $(VENV_DIR)执行make install就能完成从创建环境到安装依赖的全过程。Windows 上没有 make你也可以写一个setup.batecho off py -m venv .venv .venv\Scripts\python.exe -m pip install --upgrade pip .venv\Scripts\python.exe -m pip install -r requirements.txt这些脚本通用性很强。它们其实也说明了一个思路虚拟环境是项目工程化的一环用脚本固定创建流程比靠人脑记命令靠谱得多。4.4 性能与心智venv 在量化、爬虫、Web 开发等场景的应用量化交易、爬虫、Web 开发这三个场景恰好都能从 venv 中获益。先说量化交易你可能同时跑回测脚本和实盘脚本一个需要 pandas 0.25 兼容旧策略另一个需要 pandas 2.x 的新接口两个 venv 各自维护互不干扰。爬虫就更不用说了一个项目用 scrapy一个项目用 requests一个项目偶尔要加上 playwright每个项目都单独建 venv 可以从源头防止“这个版本怎么跑不了”的谜之问题。Web 开发里Django 和 Flask 更是依赖冻结的重灾区。Django 版本升级后ORM 某些行为会变化同一个数据库配置在两个版本下可能出现魔法差异。如果你不隔离环境线上部署和本地开发之间很可能过着“明明天天都是同一套 requirements但就是行为不对”的日子。venv 配合 Docker 使用也是常见套路在 Docker 构建阶段先创建 venv再把.venv/bin/python作为容器入口这是一种轻量级的 Python 运行时隔离方式比整镜像装系统依赖更可控。说到底venv 带来的不仅仅是依赖隔离更是一种心智上的清爽。当你看到一个项目目录里有.venv、requirements.txt、README.md、代码文件你就不需要担心“全局环境是不是又缺个包”。这种可预期的状态才是工程效率的底色。5. 常见问题与排查技巧实录5.1 明明激活了pip list 却不是预期结果这是最常见的“假激活”现象。你在终端执行了source .venv/bin/activate提示符也出现了(.venv)但是pip list依然列出全局环境里的包。出现这种问题大概率是pip命令本身被别名指向了全局环境的 pip。在 Linux/macOS 上先运行which pip在 Windows 上运行where pip。如果输出不是虚拟环境bin/pip或Scripts\pip.exe那说明你的 PATH 里有其他路径把真正的 pip 挤掉了。另一个高发原因是你在虚拟环境里调用了pip install但该虚拟环境用的不是当前 Python 版本创建的。比如你创建 venv 时用了/usr/bin/python3但系统里另外有一个pip3命令指向其他 Python。最稳妥的规避方式是永远使用python -m pip ...而不是直接pip ...python -m pip install requests python -m pip listpython -m pip能确保 pip 和当前python属于同一个环境从根上消除路径错位。5.2 Windows 上运行的绝对路径 venv 报错d:\pyth.venv\scripts... 这类 traceback 的含义与修复很多人喜欢直接敲.venv\Scripts\python.exe 脚本名.py来运行文件结果弹出长长的 traceback第一反应是“环境坏了”。但 traceback 本身并不说明 venv 坏了它只是 Python 告诉你“某个模块导入失败或某个调用出错”。具体要看最后几行。比如Traceback (most recent call last): File d:\pyth\jb\20260923.py, line 1, in module import requests ModuleNotFoundError: No module named requests这就很明显你的.venv里没有安装 requests 包。解决办法是激活虚拟环境执行python -m pip install requests。但也有一种可能报错是Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding这种情况常见于虚拟环境的pyvenv.cfg指向的基础 Python 路径失效了比如你把整个 Python 安装目录移动过或者.venv被 CtrlC、CtrlV 复制到了另一台机器。此时别再强行修了最干脆的做法是删掉.venv重新在项目目录里创建并重新安装依赖。venv 不是便携设备它绑定在创建它的基础 Python 上这个认知越早知道越省心。5.3 “python 不是内部或外部命令” 与 PATH 配置有些用户根本没有成功安装 Python执行python -m venv .venv时命令提示符直接来一句 “python 不是内部或外部命令”。这种情况分两类。第一类是 Windows 系统没把 Python 加入 PATH解决方法是重新运行 Python 安装包在“Customize installation”页面勾选 “Add Python to environment variables”或者手动把 Python 安装目录和\Scripts目录添加到环境变量 PATH。第二类是你正在 PowerShell 里但 PowerShell 的当前会话还没继承新改的环境变量重启终端或者新开一个窗口就好。还有一个容易被忽略的Windows 上按了py启动器但python命令没生效因为Python\Launcher默认会把.py关联到py但命令行python取决于 PATH。这种情况下你完全可以不依赖python命令直接用py -3 -m venv .venv后续所有 pip 操作也用py -3 -m pip一样能玩转 venv。5.4 虚拟环境中的 python 版本不对如何指定版本venv 创建的虚拟环境版本继承的是你用来执行python -m venv的那个解释器版本。如果你全局默认是 Python 3.10但项目需要 Python 3.9 的环境直接python -m venv .venv只会得到 3.10。想创建特定小版本的 venv需要显式指定解释器Windowspy -3.9 -m venv .venvmacOS / Linux前提是已安装对应的 python3.xpython3.9 -m venv .venv如果你没有装对应版本那就得先去 Python 官网下载或者在 Linux 上用apt等包管理器安装python3.9及python3.9-venv。注意venv 无法像 conda 那样跨小版本创建全新的解释器它更像是在现有解释器上做一个“投影”。如果你频繁需要不同大版本的 Python那真的应该考虑 conda 或直接用 Docker 来管理运行时而不是硬拧 venv。5.5 fatal error: Python.h: No such file or directory 这类 C 扩展安装问题有些包在pip install时如果没有预编译的 wheel会现场编译 C 扩展这时候需要 Python 的开发头文件。Linux 上常见错误是fatal error: Python.h: No such file or directory。这并不代表 venv 有问题而是基础系统缺少 Python 开发包。Debian/Ubuntu 上安装sudo apt install python3-dev build-essentialWindows 上通常不会缺Python.h反而容易因为缺少 Microsoft C Build Tools 而报错。解法是去微软官网下载安装 “Microsoft C Build Tools”或者更省事的做法是找一个对应版本的预编译 wheel 文件直接安装比如某些旧库可能只支持特定 Python 版本。遇到这类问题不用急着怨 venv先确认基础解释器是否完整。5.6 常见问题速查表下面是长期使用 venv 后我整理的一个速查表适合贴在你桌面旁边问题现象最常见原因推荐处理提示符没出现(.venv)没有 source/执行 activate检查激活命令是否符合当前 shellpip装包但python导入不到直接使用了全局 pip改用python -m pip installVSCode 运行报 ModuleNotFoundError解释器被切回全局命令面板选择.venv解释器.venv复制到别的电脑后无法运行venv 路径绑定失效删除.venv后重新创建并安装依赖想要 Python 3.9 却创建了 3.11 环境用了默认解释器显式py -3.9 -m venv或python3.9 -m venv提示未安装 pip in venvensurepip 组件缺失重装 Python 或安装相应 venv 扩展包Linux 安装 C 扩展缺 Python.h系统缺 python3-dev安装开发头文件后再试6. 写在最后我的三个长期习惯用了这么多年的 venv如果只能留下三条经验我会告诉你说第一每个项目第一件事就是创建.venv哪怕只是写个一百行的脚本也不要偷懒。第二所有相关命令统一用python -m pip ...这能帮你避开至少三成环境混乱。第三永远不要把.venv文件夹挪来挪去它就像扎根在项目里的树搬不走只能重新种。我在实际项目里还注意到一个细节创建完 venv 后先把 pip 升级到最新版再装依赖这样能减少很多包解析报错。别嫌这一步多余等你碰到过一次“pip 版本太老导致加密哈希算法不支持”的怪问题就会理解我的执着了。venv 是个再简单不过的工具但把简单工具用成习惯本身就减少了大量未来要填的坑。