4、虚拟环境入门:为什么需要虚拟环境、venv模块创建与激活、虚拟环境的工作原理

4.1 为什么需要虚拟环境?

说实话,我刚入行那会儿也踩过这个坑。

当时接手一个老项目,依赖的是 Django 2.2。我自己电脑上装的是 Django 4.0。一跑项目,直接报错——ImportError 满天飞。我花了整整一个下午排查,最后发现是版本冲突。

你想想看,Python 的包管理默认是全局安装的。所有项目共用一套 site-packages。项目A需要 requests==2.25,项目B需要 requests==2.28。装了这个,那个就崩。装了那个,这个就挂。

虚拟环境就是来解决这个问题的。

它为每个项目创建一套独立的 Python 解释器和包目录。说白了,就是给每个项目一个「隔离的小房间」。你在房间里怎么折腾,都不会影响到外面。

核心价值:依赖隔离 + 版本锁定 + 环境可复现

我个人习惯是:每个项目,从第一天起就创建虚拟环境。哪怕只是个几行代码的脚本。为什么?因为项目总会变大,依赖总会变多。到时候再迁移环境,那叫一个痛苦。

4.2 venv 模块创建与激活

Python 3.3 之后,官方内置了 venv 模块。不需要装任何第三方工具,开箱即用。

4.2.1 创建虚拟环境

打开终端,进到你的项目目录,然后执行:

python -m venv venv

这个命令的意思是:用 venv 模块,在当前目录下创建一个叫 venv 的虚拟环境目录。

执行完后,你会看到项目里多了一个 venv/ 文件夹。里面包含了:

  • bin/(Linux/Mac)或 Scripts/(Windows)—— 存放 Python 解释器和激活脚本
  • lib/ —— 存放第三方包
  • pyvenv.cfg —— 配置文件,记录虚拟环境的基本信息
小技巧:我习惯把虚拟环境目录命名为 venv 或 .venv。前者更直观,后者可以隐藏起来(Linux/Mac 下点号开头的文件默认隐藏)。记得把 venv/ 加到 .gitignore 里,别提交到版本库。

4.2.2 激活虚拟环境

创建完环境,得先激活才能用。不同操作系统命令不一样:

操作系统 Shell 激活命令
Linux / Mac bash / zsh source venv/bin/activate
Linux / Mac fish source venv/bin/activate.fish
Windows CMD venv\Scripts\activate.bat
Windows PowerShell venv\Scripts\Activate.ps1

激活成功后,你会看到终端提示符前面多了 (venv) 字样。比如:

(venv) user@machine:~/my_project$

这时候你执行 pip install,所有包都会装到这个虚拟环境里,不会污染全局。

注意:我曾经遇到过一个问题——在 Windows 的 PowerShell 里执行 Activate.ps1 报错。原因是 PowerShell 的执行策略默认禁止运行脚本。解决办法是用管理员权限执行 Set-ExecutionPolicy RemoteSigned,或者直接用 CMD 激活。

4.2.3 退出虚拟环境

很简单,一行命令:

deactivate

执行后,(venv) 前缀消失,你又回到了全局环境。

4.3 虚拟环境的工作原理

嗯,这里我们来聊聊底层原理。搞懂了原理,你遇到问题就知道怎么排查了。

4.3.1 核心机制:修改 PATH 环境变量

虚拟环境的本质,说白了就是「偷换」了 Python 解释器和包路径。

当你激活虚拟环境时,activate 脚本做了两件事:

  1. 修改 PATH 环境变量:把 venv/bin/(或 venv\Scripts\)插到 PATH 的最前面。
  2. 设置 VIRTUAL_ENV 环境变量:指向当前虚拟环境的路径。

这样一来,当你输入 python 或 pip 时,系统会优先从 venv/bin/ 里找。而这个目录下的 python 是一个软链接(或副本),指向虚拟环境自己的解释器。

看个例子,激活后执行 which python:

(venv) $ which python
/home/user/my_project/venv/bin/python

看到了吗?不再是 /usr/bin/python,而是虚拟环境里的。

4.3.2 包安装路径的变化

全局环境下,pip install 会把包装到 /usr/lib/python3.x/site-packages/ 或 ~/.local/lib/python3.x/site-packages/。

虚拟环境下,包会装到 venv/lib/python3.x/site-packages/。完全隔离,互不干扰。

你可以用这个命令验证:

(venv) $ python -c "import sys; print(sys.path)"

输出结果里,第一个路径就是虚拟环境的 site-packages 目录。

4.3.3 退出时发生了什么?

执行 deactivate 时,脚本会:

  • 恢复原来的 PATH 环境变量
  • 删除 VIRTUAL_ENV 环境变量

一切回到激活前的状态。干干净净,不留痕迹。

一句话总结:虚拟环境就是通过修改 PATH 和 sys.path,让 Python 在「错误的地方」找包,从而实现隔离。

4.4 避坑指南

最后分享几个我踩过的坑:

  • 不要移动虚拟环境目录:虚拟环境里有很多硬编码的绝对路径。一旦移动,就会失效。我建议创建时就放在项目根目录,别挪来挪去。
  • 不要用 sudo pip install:在虚拟环境里用 sudo,会把包装到全局,破坏隔离性。如果遇到权限问题,检查一下是不是没激活环境。
  • 记得生成 requirements.txt:环境配好后,执行 pip freeze > requirements.txt。这样别人拿到项目,直接 pip install -r requirements.txt 就能复现你的环境。

好了,虚拟环境的基础知识就这些。下一章我们会聊更高级的依赖管理工具——Poetry 和 Pipenv。到时候你会发现,venv 虽然简单,但有些场景确实不够用。