虚拟环境:别让包打架

虚拟环境:别让包打架

「Python 包管理全攻略」系列第三篇。这篇聊一个很多新手不理解、但老手觉得不能没有的东西------虚拟环境。

先讲个真实故事

我刚学 Python 的时候,在电脑上装了一堆包,全局的。后来做了两个项目,A 项目需要 Django 3.x,B 项目需要 Django 4.x。两个版本装在一起,直接炸了。

更离谱的是,我有一次 pip install --upgrade 升级了一个包,结果另一个项目直接跑不起来了,因为那个包的新版本去掉了一个 API。

这就是为什么需要虚拟环境------每个项目一套独立的 Python 环境,互不干扰。

虚拟环境的原理

虚拟环境说白了就是一个文件夹,里面有:

  • 一份 Python 解释器的拷贝(或链接)
  • 一个独立的 site-packages 目录(装第三方包的地方)
  • 激活脚本(用来切换环境)

激活虚拟环境后,你输入 pythonpip 指向的都是虚拟环境里的,装包也只装到这个虚拟环境里,不会污染全局。

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+PPython: 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 目录放在最前面,这样 pythonpip 命令指向虚拟环境里的版本;设置 VIRTUAL_ENV 环境变量;修改命令行提示符,加上虚拟环境名称前缀。


上一篇:pip 与包管理基础 下一篇:Conda 全面讲解

相关推荐
漠效6 小时前
随机代理‌IP访问脚本
开发语言·python
SilentSamsara6 小时前
元类与 __init_subclass__:类是如何被“创建“出来的
开发语言·python·青少年编程
隔壁大炮6 小时前
MNE-Python 第6天学习笔记:分段(Epoching)与基线校正
python·eeg·mne·脑电数据处理
SilentSamsara6 小时前
concurrent.futures 实战:进程池与线程池的统一抽象
运维·开发语言·python·青少年编程
水木流年追梦7 小时前
大模型入门-大模型的推理策略
开发语言·python·算法·正则表达式·prompt
Cthy_hy7 小时前
Python 算法竞赛:数学核心知识点全总结
python·算法
独隅7 小时前
DeepSpeed ZeRO-3在TensorFlow中缺失的底层支持机制与优化全面指南
人工智能·python·tensorflow
松☆7 小时前
昇腾NPU上的张量操作库,和PyTorch的张量操作有啥不一样?
人工智能·pytorch·python
PILIPALAPENG8 小时前
第4周 Day 4:Agent 工作流模式——编排复杂流程
前端·人工智能·python