Python 运行时、环境和虚拟环境
Python 运行时
Python 运行时指的是 使 Python 程序能够执行的一组核心文件。从结构上看,主要包含三部分:
- 解释器(interpreter)
- Python 标准库(standard library)
- 内建模块(built-in modules)
- 扩展模块(extension modules)
第三方库(如 numpy、requests)通常安装在 site-packages 中,不属于 Python 自带运行时,但在执行视角下可以视为运行时的一部分。
抽象结构:
1 | Python Runtime |
Python 运行时的目录结构
在 Linux / macOS 的典型结构如下:
1 | python-3.12/ |
说明:
| 目录 | 作用 |
|---|---|
| bin | Python 解释器 |
| lib/pythonX.Y | Python 标准库 |
| lib-dynload | Python 自带的动态扩展模块 |
| site-packages | 第三方库安装目录 |
| include | C 扩展开发所需头文件 |
在 Windows 的结构与 Linux 略有不同,但逻辑一致:
1 | Python312/ |
Python 启动时如何找到库
Python 启动后会构造 sys.path,用于查找模块:
1 | [ |
含义:
| 路径 | 内容 |
|---|---|
| script_dir / cwd | 当前脚本目录或工作目录 |
| PYTHONPATH | 用户通过环境变量 PYTHONPATH 指定的额外路径 |
| stdlib | Python 标准库 |
| lib-dynload | 内置扩展模块 |
| site-packages | 第三方库 |
Python 会根据 解释器所在目录自动推导 最后的三种路径,使其保持固定的相对路径关系。
在导入模块时,例如
1 | import requests |
Python 会按顺序在这些路径中查找。
设置 PYTHONPATH 环境变量用于添加自定义搜索路径,常用于未安装脚本的临时调试,例如
1 | PYTHONPATH=/my/path/to/sth python script.py |
pip 安装库时发生了什么
pip 在安装库时,实际就是 将包文件安装到 site-packages,并写入安装元数据。
例如执行:
1 | pip install requests |
site-packages 会加上如下两个文件夹,分别存储实际的代码和安装元数据。
1 | site-packages/ |
其中 .dist-info 目录专门记录包的安装信息,例如:
1 | METADATA |
作用分别为:
| 文件 | 用途 |
|---|---|
| METADATA | 包信息 |
| RECORD | 安装文件列表 |
| entry_points.txt | CLI 工具入口 |
| WHEEL | 构建信息 |
如果一个包定义了 CLI 入口:
1 | [project.scripts] |
安装时 pip 会生成对应的启动脚本/启动程序
1 | # Linux / macOS |
它们的作用只是按照安装时提供的说明,主动调用库中的对应函数,简化后的代码类似:
1 | from mypkg.cli import main |
小结
Python 运行时结构:
1 | Python Runtime |
关键结论:
- Python 运行时 = 解释器 + 标准库 + 内建模块和扩展模块
site-packages存放第三方库pip只是在site-packages中 写入包代码和元数据- Python 通过
sys.path查找模块
Python 环境和虚拟环境
Python 环境
系统中可以同时安装多个 Python 运行时,通常是不同版本的 Python 或不同的 Python 实现,但是由于 PATH 的优先级顺序,默认只会使用找到的第一个 Python 运行时。
所谓 切换 Python 环境,本质上是调整查找顺序,让系统使用不同的 Python 运行时。
实现的核心步骤就是修改 PATH,从而改变用户使用 python 或 python3 命令所调用的 Python 解释器。
在使用和安装库时,对应的 site-packages 位置是完全基于 Python 解释器位置进行相对路径推导的,因此切换了 Python 解释器也就附带切换了对应的环境。
环境 = 一个 Python 解释器 + 与其绑定的一组路径(sys.path)
Python 虚拟环境
虚拟环境是 Python 提供的一种隔离机制,用于创建彼此隔离的执行环境。其核心目标是:
为不同项目提供独立的第三方依赖(site-packages)环境。
虚拟环境不是独立的,必须依赖于一个已有的基础环境产生,也就是在一个基础的 Python 运行时中创建,下文中将其简称为 base。
在执行层面,可以将虚拟环境表示为:
1 | Virtual Environment |
需要强调的是:虚拟环境不等于环境,不会复制完整的 Python 运行时,虚拟环境仅对第三方库(site-packages)进行隔离,共享 base 的标准库和解释器。
由此带来的直接效果是:
- 如果创建时使用的 Python 运行时被卸载或破坏,由其产生的虚拟环境也会失效。
- 不能通过创建虚拟环境来切换 Python 版本,虚拟环境中的 Python 版本必然和 base 的 Python 版本是一样的。
虚拟环境的目录结构如下:(习惯上命名为 .venv 或 venv)
Linux / macOS:
1 | .venv/ |
Windows:
1 | .venv/ |
说明:
| 目录 | 作用 |
|---|---|
| bin / Scripts | 解释器与命令入口 |
| site-packages | 第三方库安装位置 |
| pyvenv.cfg | 虚拟环境配置核心 |
| include | C 扩展编译头文件 |
虚拟环境的行为由 pyvenv.cfg 控制,核心信息例如
1 | home = /usr/bin |
作用:
| 字段 | 含义 |
|---|---|
| home | base 的 Python 解释器位置 |
| include-system-site-packages | 是否继承 base 的 site-packages,通常都是 false |
| version | Python 版本 |
实际的内容可能有所区别,例如 venv 创建的和 uv 创建的虚拟环境,记录的信息不完全一样。
用下面的命令可以激活虚拟环境(对于bash/fish/pwsh有各自的激活脚本)
1 | source .venv/bin/activate |
激活虚拟环境的实质是下面几件事:
- 修改环境变量 PATH,使得用户优先找到虚拟环境中的 Python 解释器并使用,可以通过
which命令查看
1 | which python |
- 改变解释器前缀(prefix)
在虚拟环境中运行 Python,sys.prefix 和 sys.base_prefix 会被改变,例如
1 | sys.prefix = .venv |
- 改变
sys.path模块查找路径,尤其是site-packages路径,这是虚拟环境隔离第三方依赖的核心机制
Python 启动后构造:
1 | sys.path |
在虚拟环境中典型为:
1 | [ |
因此在虚拟环境中使用的第三方模块是与 base 隔离的。
与上一点相匹配的是安装机制,在使用虚拟环境中的
pip下载的第三方库时,第三方依赖自然也会被安装到虚拟环境的site-packages中改变 shell 的 prompt,用来提示用户位于哪个虚拟环境
退出虚拟环境的实质就是撤销这部分改动,尤其是对 PATH 和 shell prompt 的改动。
小结
环境和虚拟环境的区别可以概况为:
- 环境 = 一个 Python 解释器 + 与其绑定的一组路径(sys.path)
- 虚拟环境 = 一个虚拟的 Python 解释器(指向 base Python) + 与其绑定的一组路径(sys.path),其中 site-packages 是虚拟环境独有的
