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,所有包都会装到这个虚拟环境里,不会污染全局。
Activate.ps1 报错。原因是 PowerShell 的执行策略默认禁止运行脚本。解决办法是用管理员权限执行 Set-ExecutionPolicy RemoteSigned,或者直接用 CMD 激活。
4.2.3 退出虚拟环境
很简单,一行命令:
deactivate
执行后,(venv) 前缀消失,你又回到了全局环境。
4.3 虚拟环境的工作原理
嗯,这里我们来聊聊底层原理。搞懂了原理,你遇到问题就知道怎么排查了。
4.3.1 核心机制:修改 PATH 环境变量
虚拟环境的本质,说白了就是「偷换」了 Python 解释器和包路径。
当你激活虚拟环境时,activate 脚本做了两件事:
- 修改
PATH环境变量:把venv/bin/(或venv\Scripts\)插到PATH的最前面。 - 设置
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 虽然简单,但有些场景确实不够用。