社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

不止会用 venv!深度拆解 Python 虚拟环境底层运行原理

数据派THU • 1 月前 • 141 次点击  
图片
来源:DeepHub IMBA
本文约3000字,建议阅读5分钟

本文介绍 Python 虚拟环境底层原理,解析隔离机制、sys.path 与环境管理工具。


在很久很久以前,Python的包管理非常混乱,这导致不同的项目几乎无法同时运行,所以就出现了Python 环境管理的概念,不同项目的环境彼此隔离,开发者可以为不同项目分别管理依赖项、Python 版本和软件包。弄清其底层工作机制有助于排查依赖问题、构建可复现的应用程序,也便于管理复杂的 Python 项目。


图片

什么是 Python 环境?


从文件系统来看,Python 环境就是包含以下内容的一套目录结构:

  1. Python 解释器,或者指向解释器的符号链接

  2. 存放已安装库的 site-packages 目录

  3. 修改 shell 环境变量的激活脚本

  4. 管理软件包的 pip 和安装工具

创建虚拟环境,相当于建立一套隔离的 Python 安装。它不会干扰系统 Python,也不会影响其他项目的环境。


虚拟环境的技术组成


目录结构


执行 python -m venv myenv 后会生成以下目录结构:


 myenv/   ├── bin/ (or Scripts/ on Windows)   │   ├── python -> /usr/bin/python3  # Symlink to base interpreter   │   ├── python3 -> python   │   ├── pip   │   ├── activate                    # Bash activation script   │   ├── activate.csh                # C shell script   │   ├── activate.fish               # Fish shell script   │   └── Activate.ps1                # PowerShell script   ├── include/   │   └── python3.x/                  # C headers for building extensions   ├── lib/   │   └── python3.x/   │       └── site-packages/          # Where pip installs packages   └── pyvenv.cfg                      # Configuration file


pyvenv.cfg 文件


环境的行为由这份配置文件决定:


 home = /usr/bin   include-system-site-packages = false   version = 3.11.4   executable = /usr/bin/python3.11   command = /usr/bin/python3 -m venv /path/to/myenv


关键参数包括:

  • home:基础 Python 解释器的路径

  • include-system-site-packages:是否继承系统软件包(默认值:false)

  • version:Python 版本

  • executable:创建环境时使用的原始 Python 二进制文件


深入了解环境创建过程


第 1 步:创建目录结构


运行 python -m venv myenv 时,Python 的 venv 模块开始创建环境。它先建立基础目录及其子目录。随后复制 Python 二进制文件,或者建立指向它的符号链接。Unix 使用符号链接,Windows 则复制二进制文件。接着创建 site-packages 目录。最后写入 pyvenv.cfg 配置。


第 2 步:安装核心软件包


环境中会预装以下软件包:

  • pip:软件包安装器

  • setuptools:构建和分发工具

  • wheel:二进制软件包格式支持(可选)

安装所需文件来自下载,或者直接从基础 Python 安装中复制。


第 3 步:生成激活脚本


激活脚本因平台而异,执行时会完成四项操作:

  1. 保存当前环境状态($PATH、$PYTHONHOME)

  2. 修改环境变量

 VIRTUAL_ENV="/path/to/myenv"    PATH="$VIRTUAL_ENV/bin:$PATH"    unset PYTHONHOME  # Prevent conflicts
  1. 更改 shell 提示符,添加 (myenv) 前缀

  2. 定义 deactivate 函数,以便恢复原始状态


示例:激活期间会发生什么


 # Before activation   $ which python   /usr/bin/python      $ echo $PATH   /usr/local/bin:/usr/bin:/bin      # After: source myenv/bin/activate   $ which python   /path/to/myenv/bin/python      $ echo $PATH   /path/to/myenv/bin:/usr/local/bin:/usr/bin:/bin      $ echo $VIRTUAL_ENV   /path/to/myenv


理解 sys.path:模块搜索路径


sys.path 是一个目录路径列表。导入模块时,Python 会逐一搜索其中的目录;它也是 Python 导入系统最关键的组成部分。


sys.path 如何构建


Python 解释器启动后,按以下顺序构建 sys.path:

  1. 脚本所在目录;在交互模式下则是当前目录

  2. PYTHONPATH 环境变量中的目录(如果已设置)

  3. 取决于安装的默认路径,包括标准库位置、site-packages 目录,以及 site-packages 中的 .pth 文件


虚拟环境中的 sys.path


 import sys   print(sys.path)


激活环境后的输出:


 [       '',  # Current directory       '/path/to/myenv/lib/python3.11/site-packages',  # Virtual env packages       '/usr/lib/python3.11',                          # Standard library       '/usr/lib/python3.11/lib-dynload',              # Dynamic modules       # System site-packages EXCLUDED (if include-system-site-packages=false)   ]


导入解析如何工作


执行 import numpy 后,Python 按顺序遍历 sys.path。它会在每个目录中寻找 numpy.py(单文件模块)、numpy/__init__.py(软件包),或者 numpy.so、numpy.pyd(编译扩展)。首个匹配项会被导入;如果全部路径都没有匹配项,则引发 ModuleNotFoundError。


site 模块


Python 启动时会自动导入 site 模块。该模块负责把 site-packages 目录加入 sys.path,处理可以增加额外路径的 .pth 文件,并设置用户 site-packages(~/.local/lib/pythonX.Y/site-packages)。相关路径可以直接检查:


 import site   print(site.getsitepackages())  # ['path/to/myenv/lib/python3.11/site-packages']   print(site.getusersitepackages())  # User's site-packages directory


技术深潜:虚拟环境如何实现隔离


1、解释器发现


运行 myenv/bin/python 时,二进制文件先检查当前目录或父目录中是否存在 pyvenv.cfg。找到配置后,它读取 home 来定位基础解释器。标准库仍取自基础解释器,site-packages 则使用虚拟环境内的目录。


2、ys.prefix 机制


 import sys   print(sys.prefix)        # /path/to/myenv   print(sys.base_prefix)   # /usr (base installation)
  • sys.prefix:虚拟环境根目录

  • sys.base_prefix:原始 Python 安装目录

  • sys.prefix != sys.base_prefix:表示当前处于虚拟环境中


借助这套机制,Python 从基础安装加载标准库,却把软件包安装到虚拟环境的 site-packages。


3、为什么符号链接与复制很重要


Unix/Linux 使用符号链接,可以节省磁盘空间并自动继承基础 Python 的更新;如果基础 Python 被移除,链接也可能随之失效。


Windows 复制二进制文件,占用的磁盘空间更多,却不会因基础 Python 发生变更或被移除而受影响,所以Python 更新后必须重新创建虚拟环境。


环境管理工具比较


venv(内置,Python 3.3+)


优点:

  • 不需要外部依赖

  • 属于官方标准

  • 轻量

缺点:

  • 无法为不同 Python 版本创建环境

  • 功能比替代工具少

virtualenv(第三方)


优点:

  • 支持 Python 2.7+

  • 创建环境更快

  • 配置选项更多

  • 可以使用不同的 Python 版本

技术差异在于,virtualenv 使用发现机制寻找 Python 解释器。


conda(Anaconda/Miniconda)


优点:

  • 一并管理 Python 版本和软件包

  • 能处理非 Python 依赖项,包括 C 库和 R 软件包

  • 采用二进制软件包分发

技术架构:

  • 完全独立于 pip

  • 使用自己的软件包索引和依赖求解器

  • 创建完整的 Python 安装,而不只是一套虚拟环境


进阶:动态修改 sys.path


1、 直接操作


 import sys   sys.path.insert(0, '/custom/path/to/modules')   import my_custom_module


2、使用 .pth 文件


创建 myenv/lib/python3.11/site-packages/custom.pth:


 /path/to/my/modules   /another/path


启动时,这些路径会自动加入 sys.path。


3、使用 PYTHONPATH


 export PYTHONPATH=/path/to/modules:$PYTHONPATH   python script.py


警告:PYTHONPATH 会影响所有 Python 进程,可能引发冲突。


环境管理一些技巧


  1. 每个项目使用一个环境,避免依赖冲突

  2. 使用 requirements.txt 固定版本,保证环境可复现

  • pip freeze > requirements.txt pip install -r requirements.txt

  1. 切勿提交虚拟环境,应将其加入 .gitignore

  2. 记录 Python 版本,可使用 .python-version 或在 README 中说明

  3. 使用环境变量,在代码之外存储密钥和配置


调试环境问题


检查正在运行哪个 Python


 import sys   print(sys.executable)      # /path/to/myenv/bin/python   print(sys.prefix)          # /path/to/myenv   print(sys.path)            # Module search paths


验证软件包位置


 import numpy   print(numpy.__file__)  # Should be in your virtual env's site-packages


检查名称遮蔽


 # If wrong module is imported, check sys.path order   python -c "import sys; print('\n'.join(sys.path))"


总结


Python 环境不只是一组隔离目录。文件系统组织(site-packages、bin 目录)、配置文件(pyvenv.cfg)、环境变量(PATH、VIRTUAL_ENV、PYTHONPATH)、运行时内省(sys.path、sys.prefix)和导入钩子(site 模块)共同构成了整套系统。


理解这些机制,才能妥善排查复杂的依赖问题、构建自定义部署 Pipeline,并设计稳健的 Python 应用程序。sys.path 的模块搜索机制配合虚拟环境隔离,既保留 Python 的灵活性,也维持各项目之间的独立性。


作者:Darshika pundir


编辑:于腾凯

校对:林亦霖



关于我们

数据派THU作为数据科学类公众号,背靠清华大学大数据研究中心,分享前沿数据科学与大数据技术创新研究动态、持续传播数据科学知识,努力建设数据人才聚集平台、打造中国大数据最强集团军。



Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/200586