把 Python 环境理顺:终端、pyenv、虚拟环境与包管理器各管什么

2026-09-10 33 预计阅读时间: 1 分钟
来源: realpython.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

Python 项目中的很多“代码问题”,实际上是环境问题:终端启动了不同的 shell、python 指向了意外的解释器、依赖装进了全局环境,或者 pip 与当前 Python 根本不是同一套安装。要建立一个稳定、可复现的开发环境,关键不是记住更多命令,而是分清每层工具的职责。

先画清环境的四个层次

一个典型的 Python 开发环境可以拆成四层:

层次 常见工具 主要职责
交互入口 Terminal、Windows Terminal、iTerm 等 显示输入输出,承载命令行会话
命令解释 Bash、Zsh、PowerShell 解析命令、变量、管道和启动脚本
Python 版本 pyenv、系统 Python 决定使用 Python 3.10、3.11 还是其他版本
项目与依赖 venv、pip、Poetry 隔离项目环境,安装并记录第三方包

终端和 shell 并不是同一个东西。终端是运行 shell 的界面,shell 才负责解释 cd、环境变量和脚本。更换终端应用通常不会自动改变 Python;更换 shell 或它的启动配置,却可能改变 PATH,进而让 python 指向另一套解释器。

可以用下面这些命令检查当前会话究竟在使用什么:

printf 'shell=%s\n' "$SHELL"
command -v python
python --version
python -c 'import sys; print(sys.executable)'
python -m pip --version

最后两行尤其重要。sys.executable 给出当前解释器的真实路径,python -m pip --version 则会显示 pip 所属的位置。两者应当落在同一个预期环境中。

pyenv 与虚拟环境解决的是不同问题

pyenv 主要用于选择 Python 解释器版本。虚拟环境则基于某个解释器,为单个项目创建隔离的安装目录。它们可以配合,但不能相互替代。

可以这样实践一个普通项目环境。以下示例假设已经安装 pyenv,并且系统提供 Bash 或 Zsh:

mkdir environment-demo
cd environment-demo

pyenv install -s 3.12.3
pyenv local 3.12.3

python -m venv .venv
source .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install requests

python -c 'import sys, requests; print(sys.executable); print(requests.__version__)'

Windows PowerShell 中,激活命令通常改为:

.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip

这里的执行顺序很关键:先让 pyenv 选择基础解释器,再用这个解释器创建 .venv。创建以后,虚拟环境不会随着 .python-version 的修改自动换成另一个 Python 版本。需要升级基础版本时,通常应重新创建虚拟环境并重新安装依赖。

.venv 目录不应提交到版本库,可以在 .gitignore 中加入:

.venv/
__pycache__/
*.py[cod]

pip 与 Poetry:选择一种清晰的依赖工作流

pip 负责把包安装进某个 Python 环境。它很基础,也很可靠,但项目需要自行决定如何记录直接依赖、锁定版本和构建发布包。

一个小型应用可以采用 venv、pip 和需求文件:

python -m venv .venv
source .venv/bin/activate
python -m pip install requests==2.32.3
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt

需要注意,pip freeze 会记录当前环境中的全部已安装包,包括间接依赖。它适合生成可重复安装的环境快照,但不一定适合作为人工维护的顶层依赖清单。

Poetry 把依赖声明、锁文件、虚拟环境和项目打包整合到同一套工作流中。可以这样建立一个最小项目:

mkdir poetry-demo
cd poetry-demo
poetry init --no-interaction
poetry add requests
poetry run python -c 'import requests; print(requests.__version__)'
poetry env info

团队采用 Poetry 时,应提交 pyproject.toml 和锁文件,而不是提交虚拟环境目录。运行命令时使用 poetry run ...,可以减少忘记激活环境造成的歧义。

不要在同一个项目里无规则地混用 pip freeze、手写 requirements.txt 和 Poetry 锁文件。工具并非不能共存,但必须明确哪个文件是依赖的权威来源,否则本地环境与持续集成环境很容易产生差异。

用故障现象反查环境层次

遇到 ModuleNotFoundError 时,不要立即再次执行 pip install。先收集解释器与安装位置:

python -c 'import sys; print(sys.executable)'
python -m pip --version
python -m pip show requests
python -c 'import site; print(*site.getsitepackages(), sep="\n")'

常见判断方式如下:

  • pythonpip 路径不属于同一环境:改用 python -m pip
  • 激活环境后路径仍指向系统 Python:检查 shell 的 PATH、别名和启动脚本。
  • pyenv 版本正确,但包仍然缺失:包可能装在另一个虚拟环境中。
  • 本地可以运行,CI 无法运行:检查是否提交了依赖声明和锁文件,以及 CI 使用的 Python 版本。
  • IDE 与终端行为不同:IDE 可能选择了另一条解释器路径,需要在项目设置中显式指定 .venv

一个简短的自测

在不执行命令的情况下,先回答下面几个问题:

  1. 更换终端应用是否必然改变 Python 版本?不必然,真正影响解析结果的是 shell 配置与 PATH 等环境设置。
  2. pyenv 选择 Python 3.12 后,旧 .venv 是否自动升级?不会,虚拟环境通常需要重建。
  3. 为什么推荐 python -m pip?因为它明确要求当前 python 解释器运行对应的 pip 模块。
  4. 是否应该提交 .venv?通常不应提交;应提交依赖声明和必要的锁文件。
  5. Poetry 项目是否必须先手动激活环境?不一定,可以使用 poetry run 在项目环境中执行命令。

建立可预测环境的检查清单

开始编码前,确认 python --version 与项目要求一致,并通过 sys.executable 检查解释器路径。每个项目使用独立虚拟环境,只选择一套主要依赖管理流程,并把版本声明与锁文件纳入版本控制。

排查问题时,从终端、shell、PATH、Python 解释器、虚拟环境到包安装位置逐层确认。环境管理的目标不是堆叠更多工具,而是让每位开发者和 CI 都能明确回答两个问题:现在运行的是哪个 Python,以及依赖究竟安装在哪里。


相关推荐