虚拟环境:别让包打架
「Python 包管理全攻略」系列第三篇。这篇聊一个很多新手不理解、但老手觉得不能没有的东西------虚拟环境。
先讲个真实故事
我刚学 Python 的时候,在电脑上装了一堆包,全局的。后来做了两个项目,A 项目需要 Django 3.x,B 项目需要 Django 4.x。两个版本装在一起,直接炸了。
更离谱的是,我有一次 pip install --upgrade 升级了一个包,结果另一个项目直接跑不起来了,因为那个包的新版本去掉了一个 API。
这就是为什么需要虚拟环境------每个项目一套独立的 Python 环境,互不干扰。
虚拟环境的原理
虚拟环境说白了就是一个文件夹,里面有:
- 一份 Python 解释器的拷贝(或链接)
- 一个独立的 site-packages 目录(装第三方包的地方)
- 激活脚本(用来切换环境)
激活虚拟环境后,你输入 python 和 pip 指向的都是虚拟环境里的,装包也只装到这个虚拟环境里,不会污染全局。
venv:Python 自带的方案
从 Python 3.3 开始,虚拟环境工具 venv 就是标准库的一部分了,不用额外安装。
创建虚拟环境
bash
# 在项目目录下创建
cd my-project
python3 -m venv .venv
这会在当前目录创建一个 .venv 文件夹。用 .venv 这个名字是社区惯例,以点开头方便隐藏,而且大多数 .gitignore 模板已经默认忽略它了。
激活虚拟环境
bash
# Linux / macOS
source .venv/bin/activate
# Windows CMD
.venv\Scripts\activate.bat
# Windows PowerShell
.venv\Scripts\Activate.ps1
激活之后你的命令行提示符前面会多出个 (.venv),表示当前在虚拟环境里。
在虚拟环境里干活
bash
# 装包,只装到 .venv 里
pip install flask requests
# 看看装了啥
pip list
# 导出依赖
pip freeze > requirements.txt
退出虚拟环境
bash
deactivate
就这么简单。
venv 的局限
- 只能创建和当前 Python 版本一样的虚拟环境。你系统装的是 3.12,就只能创建 3.12 的虚拟环境
- 不能管理 Python 版本本身
- 功能比较基础
如果你需要更强大的功能,往下看。
virtualenv:venv 的增强版
virtualenv 是 venv 的前身,现在作为第三方包继续维护。它比 venv 快,而且有一些额外的功能。
bash
# 安装
pip install virtualenv
# 创建虚拟环境
virtualenv .venv
# 指定 Python 版本(前提是你系统上装了这个版本)
virtualenv -p python3.10 .venv
日常使用的话,venv 和 virtualenv 差别不大。如果你需要指定 Python 版本创建虚拟环境,virtualenv 更方便。
virtualenvwrapper:管理多个虚拟环境
如果你有十几个项目,每个都有自己的虚拟环境,记哪个在哪挺烦的。virtualenvwrapper 把所有虚拟环境集中管理:
bash
pip install virtualenvwrapper
# 在 shell 配置文件里加上
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
然后就可以:
bash
# 创建虚拟环境
mkvirtualenv myproject
# 切换虚拟环境(不用记路径)
workon myproject
# 列出所有虚拟环境
lsvirtualenv
# 删除虚拟环境
rmvirtualenv myproject
Windows 用户对应的工具是 virtualenvwrapper-win。
不过说实话,现在用 virtualenvwrapper 的人越来越少了,因为更好的工具出现了。
现代方案:让工具帮你管虚拟环境
Poetry
bash
pip install poetry
cd my-project
poetry init # 初始化项目
poetry add flask # 添加依赖,自动创建虚拟环境
poetry shell # 进入虚拟环境
Poetry 会自动在项目里创建和管理虚拟环境,你不用手动 python -m venv 了。它还用 pyproject.toml 替代了 requirements.txt,管理依赖更现代。
uv(后面有专篇)
uv 是目前最快的 Python 包管理器,也能管理虚拟环境:
bash
uv venv # 创建虚拟环境
uv pip install flask # 在虚拟环境里装包
速度快到什么程度?同样的操作,uv 比 pip 快 10-100 倍。
虚拟环境的最佳实践
1. 每个项目一个虚拟环境
这是铁律。别偷懒全局装包,迟早出事。
2. 把虚拟环境加到 .gitignore
text
# .gitignore
.venv/
env/
__pycache__/
*.pyc
虚拟环境是本地的东西,不应该提交到 Git。每个人拿到代码后自己创建虚拟环境、装依赖。
3. 配合 requirements.txt 使用
bash
# 新同事拿到项目后
cd project
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
三步搞定,环境一致。
4. IDE 里选择正确的解释器
VS Code 里 Ctrl+Shift+P → Python: Select Interpreter → 选你项目里的 .venv。
PyCharm 在项目设置里配置 Python 解释器,指向虚拟环境。
不选对解释器,IDE 会报一堆 import 找不到的错误,代码其实没问题,就是 IDE 不知道你的包装在哪。
常见坑和解法
坑 1:虚拟环境里找不到系统包
默认情况下,虚拟环境和全局环境是隔离的。如果你有一些全局装的包(比如 systemd-python 这种和系统绑定的),在虚拟环境里用不了。
bash
# 创建时加上 --system-site-packages
python3 -m venv --system-site-packages .venv
这样虚拟环境可以访问全局包,但自己装的包还是隔离的。
坑 2:虚拟环境的 Python 版本不对
venv 创建的虚拟环境版本和当前 Python 一样。如果你需要特定版本,先用 pyenv 装好那个版本,再用 pyenv 的 Python 创建虚拟环境:
bash
pyenv install 3.10.14
pyenv local 3.10.14
python -m venv .venv # 这个 .venv 就是 3.10 的了
坑 3:PowerShell 不让执行激活脚本
Windows 的 PowerShell 默认不允许执行脚本。解决办法:
powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
面试题
1. 虚拟环境解决了什么问题?为什么不能所有项目共用全局 Python 环境?
虚拟环境解决了包依赖隔离的问题。不同项目可能依赖同一个包的不同版本,共用全局环境会导致版本冲突。另外,全局环境装太多包也会让依赖关系混乱,排查问题困难。虚拟环境让每个项目有独立的包空间,互不干扰。
2. venv 和 virtualenv 有什么区别?
venv 是 Python 标准库自带的,virtualenv 是第三方包。virtualenv 功能更丰富,创建速度更快,支持指定 Python 版本创建虚拟环境(前提是系统已安装该版本)。venv 只能创建和当前 Python 版本一致的环境。日常使用差别不大。
3. 虚拟环境应该提交到 Git 仓库吗?为什么?
不应该。虚拟环境包含二进制文件(Python 解释器、编译的包),这些文件和操作系统、架构绑定,在不同机器上无法使用。正确做法是把虚拟环境目录加入 .gitignore,通过 requirements.txt 或 pyproject.toml 管理依赖,每个人拿到代码后自行创建虚拟环境并安装依赖。
4. 解释一下 source .venv/bin/activate 这条命令做了什么。
source是 shell 命令,在当前 shell 进程中执行脚本(而不是开一个子 shell)。activate 脚本主要做了三件事:修改 PATH 环境变量,把虚拟环境的 bin 目录放在最前面,这样python和pip命令指向虚拟环境里的版本;设置 VIRTUAL_ENV 环境变量;修改命令行提示符,加上虚拟环境名称前缀。
上一篇:pip 与包管理基础 下一篇:Conda 全面讲解