一、先搞懂 pyenv:Python 版本的"总管家"
1. pyenv 是什么?
pyenv 是一款 跨平台的 Python 版本管理器 (核心用 Shell 编写),核心作用是:在一台机器上安装/切换多个独立的 Python 版本,且版本之间互不干扰。
你可以把它理解成"Python 版本超市":
- 系统自带的 Python 是"默认货架"(比如 macOS 自带 Python 2.7);
- pyenv 允许你"买"(安装)不同版本的 Python(3.10.8、3.11.6、3.12.0),并自由切换"当前用哪个货架的 Python";
- 它不替代 Python,只是"管理多个 Python 解释器的安装和调用"。
2. pyenv 和 Python 的核心关系
| 角色 | 作用 |
|---|---|
| Python | 核心解释器(执行代码的程序),每个版本是独立的可执行文件+库文件 |
| pyenv | 管理工具: 1. 帮你下载/编译/安装不同版本的 Python; 2. 拦截终端的 python/pip 命令,指向你指定的 Python 版本 |
举个例子:
- 没装 pyenv 时,终端输入
python --version,调用的是系统默认 Python(比如 2.7); - 装了 pyenv 并切换到 3.10.8 后,输入
python --version,调用的是 pyenv 安装的 3.10.8,系统默认版本不受影响。
3. pyenv 的核心解决的问题
- 全局版本冲突:比如系统依赖 Python 2.7,但你的项目需要 Python 3.10,直接改全局版本会导致系统功能异常,pyenv 可切换"局部/全局"版本;
- 多版本共存:不同项目需要不同 Python 版本(比如 A 项目 3.10,B 项目 3.11),pyenv 可给每个项目指定专属版本;
- 干净安装:避免手动编译 Python 时的依赖、路径问题(pyenv 封装了编译逻辑)。
二、再理解 .venv:项目的"专属依赖储物柜"
1. .venv 是什么?干嘛用的?
.venv 是 Python 虚拟环境(Virtual Environment)的默认目录名(也常用 venv),核心作用是:为单个项目隔离依赖包,避免不同项目的包版本冲突。
你可以把它和 pyenv 做对比(关键区分!):
| 工具 | 管理对象 | 核心目的 | 作用范围 |
|---|---|---|---|
| pyenv | Python 解释器版本(3.10/3.11) | 解决"用哪个版本的 Python 运行代码" | 全局/局部(多项目) |
| .venv | Python 依赖包(pip 安装的包) | 解决"这个项目用哪些版本的包" | 单个项目 |
举个具体场景:
- 项目 A 需要
requests==2.25.0,项目 B 需要requests==3.0.0; - 若直接全局安装,装了 3.0.0 会覆盖 2.25.0,导致项目 A 报错;
- 给每个项目创建
.venv,项目 A 的.venv里装 2.25.0,项目 B 的.venv里装 3.0.0,彼此完全隔离。
.venv 目录里包含:
- 独立的 Python 解释器(复制了 pyenv/系统的某个 Python 版本);
- 独立的
pip工具; - 独立的
site-packages目录(存放该项目的所有依赖包)。
2. .venv 怎么创建?
Python 3.3+ 内置了 venv 模块(无需额外安装),创建步骤如下(前提:先确定当前用的 Python 版本):
步骤1:用 pyenv 切换到目标 Python 版本(选模具), 如果是创建.venv只需按照带序号步骤执行。
bash
# 1. 确保已用 pyenv 安装目标版本(比如 3.10.8)
pyenv install 3.10.8
# 2. 切换到该版本(仅当前终端生效)
pyenv local 3.10.8 # 或全局切换:pyenv global 3.10.8
# 切换 pyenv 版本后(未创建虚拟环境)
# 此时你用的是pyenv安装的解释器,存放在用户主目录的pyenv版本库里,属于「系统级(用户级)」,而非虚拟环境。
# 查看当前 Python 解释器的路径
which python
# 输出示例:/Users/你的用户名/.pyenv/shims/python
# 追根溯源:shims是pyenv的"转发器",实际指向 pyenv 安装的版本
pyenv which python
# 输出示例:/Users/你的用户名/.pyenv/versions/3.10.8/bin/python
# 3. 验证版本(确保是 3.10.8)
python --version
~/.pyenv/versions/3.10.8/bin/python就是此时的「真实解释器路径」(pyenv 管理的系统级解释器);~/.pyenv/shims/python是 pyenv 的"转发器",作用是把python命令转发到上面的真实路径。
步骤2:在项目根目录创建 .venv(用模具复刻)
bash
# 1.进入项目目录(比如你的 SentenceSplitter)
cd /Users/luojia/Desktop/projects/SentenceSplitter
# 2.创建虚拟环境(.venv 是目录名,可自定义,比如 venv)
python -m venv .venv
#执行后,项目根目录会出现.venv隐藏目录(macOS/Linux 下 `.` 开头是隐藏文件,`ls -a`可查看)。
底层实现:
执行 python -m venv .venv 时,Python 会做两件事:
- 在
.venv目录下创建bin(macOS/Linux)/Scripts(Windows)目录; - 把
~/.pyenv/versions/3.10.8/bin/python复制一份 到.venv/bin/python(硬链接/拷贝,本质是同一个文件的副本)。
验证路径:
bash
# 查看 .venv 里的解释器路径
ls -la .venv/bin/python
# 输出示例:lrwxr-xr-x 1 你的用户名 staff 34 1 10 12:00 .venv/bin/python -> /Users/你的用户名/.pyenv/versions/3.10.8/bin/python
# (注:macOS 下是软链接,Linux 下可能是硬链接/拷贝,本质都是"复制版")
步骤3: 激活/使用 .venv
创建后需要"激活"虚拟环境,终端才会优先使用该环境的 Python/pip:
bash
# macOS/Linux 激活命令
source .venv/bin/activate
# Windows(CMD)激活命令
.venv\Scripts\activate.bat
# Windows(PowerShell)激活命令
.venv\Scripts\Activate.ps1
激活后,终端提示符会多一个 (.venv) 标识,比如:
(.venv) ➜ SentenceSplitter git:(feature/sentence-split) ✗
此时:
- 输入
python --version→ 是虚拟环境的 Python 版本(即创建时用的 3.10.8); - 输入
pip install xxx→ 包会装到.venv/lib/python3.10/site-packages,仅该项目可用; - 输入
deactivate→ 退出虚拟环境,回到系统/pyenv 的全局 Python。
底层实现:
激活 .venv 时,终端会修改 PATH 环境变量------把 .venv/bin 放到 PATH 最前面,导致:
- 输入
python时,终端优先找.venv/bin/python(虚拟环境内的复制版); - 输入
pip时,优先找.venv/bin/pip(虚拟环境内的 pip)。
验证:
bash
# 激活虚拟环境
source .venv/bin/activate
# 查看当前 Python 路径(已切换到虚拟环境内)
which python
# 输出示例:/Users/你的用户名/项目目录/SentenceSplitter/.venv/bin/python
# 查看版本(和 pyenv 切换的版本一致)
python --version # Python 3.10.8
注:先通过pyenv(或直接指定版本号)让终端生效目标Python版本 → 用这个版本的python -m venv .venv创建虚拟环境 → 虚拟环境复制该版本,实现版本指定
避坑:
1. 若不切换版本,会怎么样?
如果直接用系统默认版本(比如macOS自带的2.7)创建虚拟环境:
bash
# 没切换pyenv,终端默认是Python 2.7
python --version # 输出:Python 2.7.18
# 用2.7创建虚拟环境
python -m venv .venv # 会报错!因为Python 2.7没有内置venv模块
这就是为什么必须先切换到目标版本(3.3+),再创建虚拟环境 ------ 虚拟环境的版本完全依赖"创建时用的python命令对应的版本"。
2. 虚拟环境是"复制"而非"引用"
创建虚拟环境时,会把当前Python版本的解释器、核心库完整复制一份 到.venv目录里:
- 即使后续改了pyenv的全局版本(比如切换到3.11.6),已创建的
.venv里的版本还是3.10.8; - 若想改虚拟环境的版本,只能删除旧的
.venv,切换 pyenv 到新版本,重新创建即可。
3.除了pyenv,还有其他切换版本的方式吗?
有!比如你的系统里装了多个Python版本(如python3.10、python3.11),可以直接用版本号指定,无需pyenv:
bash
# 直接用python3.10命令创建3.10版本的虚拟环境(无需pyenv切换)
python3.10 -m venv .venv
本质还是"先确定目标版本的python命令,再用它创建虚拟环境" ------ pyenv只是让"切换版本"更方便的工具。
4.和"系统原生解释器"的区别 :
系统原生解释器(如 macOS 的 /usr/bin/python)是操作系统自带的,pyenv 管理的解释器是你手动安装的(~/.pyenv/versions/),虚拟环境的解释器是从 pyenv 复制的------三者相互独立。
三、查看 Python 版本的核心命令(分场景,覆盖所有需求)
不同场景下查看版本的命令不同,核心分「查当前生效版本」「查系统所有版本」「查 pyenv 管理版本」三类,以下是 macOS/Linux 通用命令(Windows 差异最后补充):
| 需求 | 命令 | 说明 |
|---|---|---|
| 查「当前终端生效」的 Python 版本 | python --version(简写 python -V) python3 --version(区分2/3) |
激活虚拟环境则显示虚拟环境版本;未激活则显示 pyenv/系统默认版本 |
| 查「系统中安装的所有 Python」(不含 pyenv) | whereis python ls /usr/bin/python* ls /usr/local/bin/python* |
whereis 找系统级可执行文件;ls 直接列常见路径下的 Python 可执行文件 |
| 查「pyenv 管理的所有版本」(核心!) | pyenv versions |
列出 pyenv 已安装的所有版本(含系统版本),* 标注当前生效版本 |
| 查「虚拟环境内」的 Python 版本 | 先激活:source .venv/bin/activate 再查:python --version |
虚拟环境版本是创建时复制的 pyenv/系统版本,和外部隔离 |
| 查 Python 解释器「自身路径+版本」(内置) | python -c "import sys; print(sys.executable); print(sys.version)" |
同时输出解释器路径 + 详细版本信息(含编译器/系统) |
示例输出(直观理解)
bash
# 1. pyenv versions 输出(* 是当前生效版本)
system
3.10.8
* 3.11.6 (set by /Users/xxx/SentenceSplitter/.python-version)
# 2. python -c 输出(激活虚拟环境后)
/Users/xxx/SentenceSplitter/.venv/bin/python
3.11.6 (main, Oct 8 2023, 05:06:43)
[Clang 14.0.0 (clang-1400.0.29.202)]
四、Python 安装后的存储路径(分场景)
Python 路径分「系统原生」「pyenv 管理」「虚拟环境」三类,路径完全不同,以下是 macOS/Linux 核心路径:
1. 系统原生 Python(操作系统自带/手动装的,非 pyenv)
| 系统 | 路径示例 | 说明 |
|---|---|---|
| macOS | Python2:/usr/bin/python//usr/bin/python2.7 Python3:/usr/bin/python3(Xcode 自带) |
系统级路径,权限高,不建议修改 |
| Linux(Ubuntu) | Python2:/usr/bin/python2.7 Python3:/usr/bin/python3.8 |
系统默认路径 |
2. pyenv 安装的 Python(所有版本集中存储)
pyenv 会把所有安装的 Python 版本统一放在 ~/.pyenv/versions/ 目录下(~ 是用户主目录),每个版本一个独立子目录:
bash
# 查看 pyenv 安装目录结构
ls ~/.pyenv/versions/
# 输出示例:3.10.8 3.11.6 (每个文件夹对应一个版本)
# 查看 3.10.8 版本的核心文件路径
ls ~/.pyenv/versions/3.10.8/
# 关键子目录:
# - bin/python:Python 解释器可执行文件
# - lib/python3.10:核心库文件(如 os、sys 模块)
# - include/python3.10:编译用的头文件
# - bin/pip:该版本对应的 pip 工具
3. 虚拟环境内的 Python 路径
虚拟环境的 Python 是「从 pyenv/系统复制的副本」,存储在项目目录的 .venv/bin/ 下(Windows 是 .venv/Scripts/):
bash
# 激活虚拟环境后查路径
source .venv/bin/activate
which python # 输出:/Users/xxx/SentenceSplitter/.venv/bin/python
# 未激活时直接查绝对路径
ls -la .venv/bin/python
# 输出示例(macOS 是软链接,指向 pyenv 版本):
# lrwxr-xr-x 1 xxx staff 34 1 10 12:00 .venv/bin/python -> /Users/xxx/.pyenv/versions/3.10.8/bin/python
4. 快速定位当前生效 Python 的路径(通用命令)
bash
# 方式1:which(查找可执行文件路径)
which python # 当前生效的 Python 路径
which python3 # 区分 Python2/3
# 方式2:pyenv which(跳过 pyenv 转发器,查真实路径)
pyenv which python # 输出:~/.pyenv/versions/3.10.8/bin/python
五、Windows 系统补充(差异点)
Windows 路径和命令略有不同,但核心逻辑一致:
| 操作 | Windows 命令/路径 |
|---|---|
| 查当前版本 | python --version(CMD/PowerShell) |
| 查所有版本 | where python(PowerShell)、where.exe python(CMD) |
| pyenv-win 安装路径 | %USERPROFILE%\.pyenv\pyenv-win\versions\(用户目录下) |
| 虚拟环境路径 | 项目目录.venv\Scripts\python.exe |
六、关键补充(避坑)
1..venv 要不要提交到 Git?
绝对不要!
.venv 目录体积大(几十MB),且是本地环境相关的,提交到 Git 会污染仓库。
解决:在 .gitignore 文件中添加 .venv/,Git 会忽略该目录;同时用 requirements.txt 记录依赖:
bash
# 激活虚拟环境后,导出依赖到 requirements.txt
pip freeze > requirements.txt
# 别人拿到项目后,创建虚拟环境,安装依赖
pip install -r requirements.txt
2.常见问题:激活.venv后 Python 版本不对?
- 原因:创建
.venv时,pyenv 切换的版本不是目标版本; - 解决:删除旧的
.venv→ 重新切换 pyenv 到目标版本 → 重新创建.venv。
3.pyenv 安装的 Python 在哪?
pyenv 安装的所有 Python 版本都在 ~/.pyenv/versions/ 目录下(比如 3.10.8 在 ~/.pyenv/versions/3.10.8/),.venv 会复制该目录下的 Python 解释器。
4.pyenv versions 是查看「pyenv 安装版本」的专属命令,whereis python 看不到 pyenv 版本(因为 pyenv 用 shims 转发)
5.虚拟环境的 Python 路径是「副本」,即使删除 pyenv 对应的版本,虚拟环境内的解释器依然可用
6.若 python --version 显示的版本和预期不符,先查 which python 看路径,大概率是 PATH 环境变量优先级问题(激活虚拟环境会改 PATH)。