写点什么

Python 虚拟环境:原理解析与最佳实践

  • 2025-01-02
    福建
  • 本文字数:4326 字

    阅读完需:约 14 分钟

从一个困境说起


小王最近遇到了一个棘手的问题:他在维护两个 Python 项目,一个是去年开发的数据分析系统,依赖 TensorFlow 1.x;另一个是最近在做的预测模型,需要用到 TensorFlow 2.x 的新特性。每次切换项目时,他都要手动更改 Python 包的版本,这不仅繁琐,而且经常出错。


"难道就没有办法让每个项目使用自己的专属 Python 环境吗?"小王在项目组会议上提出这个问题。


事实上,这个问题在 Python 社区早已有了完善的解决方案:虚拟环境(Virtual Environment)。今天,让我们从原理到实践,全面了解 Python 虚拟环境。


虚拟环境的本质


在深入了解虚拟环境之前,我们先要理解 Python 的包管理机制。当你在系统中安装 Python 时,会得到:


  1. Python 解释器:负责执行 Python 代码的程序

  2. 标准库:Python 内置的库,如 ossys 等

  3. site-packages:第三方包的安装目录


当我们执行 python 命令时,系统会:


import sysprint(sys.path)  # 你会看到 Python 搜索模块的路径列表
复制代码


这个路径列表决定了 Python 从哪里导入模块。那么,虚拟环境是如何工作的呢?


实际上,虚拟环境并不是完整的 Python 副本,而是创建了一个独立的环境目录,其中:


  1. bin/ 或 Scripts/(Windows)目录包含 Python 解释器的符号链接

  2. lib/site-packages/ 目录存放该环境的第三方包

  3. pyvenv.cfg 文件保存环境配置信息


让我们创建一个虚拟环境来验证:


python -m venv my_project_env
复制代码


查看生成的目录结构:


my_project_env/├── bin/               # Unix 系统│   ├── python        # 符号链接到系统 Python│   ├── pip│   └── activate      # 激活脚本├── lib/│   └── python3.x/│       └── site-packages/└── pyvenv.cfg        # 配置文件
复制代码


当我们激活虚拟环境时:


# Unix 系统source my_project_env/bin/activate
# Windows.\my_project_env\Scripts\activate
复制代码


activate 脚本会修改环境变量,主要是:


  1. 修改 PATH,使虚拟环境的 bin 目录优先

  2. 修改 PYTHON_PATH

  3. 添加环境标识(命令提示符前的环境名)


PYTHON_PATH 是一个环境变量,用于告诉 Python 解释器在哪里查找模块和包。具体来说,它可以用来指定额外的目录,这些目录中可能包含你希望 Python 能够访问的模块。


venv vs conda:深度对比


说到虚拟环境,很多人会问:"venv 和 conda 有什么区别?我该用哪个?"


让我们通过一个具体例子来对比。假设我们要创建一个数据科学项目的环境:


使用 venv:


python -m venv ds_projectsource ds_project/bin/activatepip install numpy pandas scikit-learn
复制代码


使用 conda:


conda create -n ds_project python=3.8conda activate ds_projectconda install numpy pandas scikit-learn
复制代码


表面上看,两者很相似,但实际上有本质区别:


1、隔离级别

venv 只隔离 Python 包

conda 可以隔离任何依赖(包括 C 库、系统包)


2、Python 版本

venv 使用创建环境时的 Python 版本

conda 可以任意指定 Python 版本


3、包管理

venv 使用 pip,从 PyPI 安装包

conda 使用自己的包管理系统,可以处理复杂的依赖关系


但是基于 venv 更加方便部署,因为其是 python 自带的,不需要额外安装,而 conda 则需要额外安装。


从零开始:venv 实战


让我们通过一个实际项目来掌握 venv 的使用。假设我们要开发一个网页数据抓取项目,需要用到 requests 和 beautifulsoup4


创建与激活


首先,选择一个合适的项目目录:


mkdir web_scrapercd web_scraperpython -m venv .venv  # 使用 .venv 作为虚拟环境目录名是一个常见约定
复制代码


激活环境:


# Unix/macOSsource .venv/bin/activate
# Windows.\.venv\Scripts\activate
复制代码


激活后,命令提示符会变成:


(.venv) $ 
复制代码


安装依赖包


现在我们可以安装项目需要的包了:


pip install requests beautifulsoup4
复制代码


值得注意的是,此时 pip list 只会显示这个环境中的包,非常清爽:


Package         Version------------   -------beautifulsoup4 4.9.3requests       2.26.0pip            21.3.1setuptools     58.1.0
复制代码


依赖管理


为了方便项目共享和部署,我们应该导出依赖列表:


pip freeze > requirements.txt
复制代码


团队其他成员可以直接通过这个文件还原环境:


pip install -r requirements.txt
复制代码


深入理解:虚拟环境的内部机制


Python 路径搜索机制


让我们写个小程序来观察虚拟环境如何改变 Python 的模块搜索路径:


# check_paths.pyimport sysimport os
def print_paths(): print("Python executable:", sys.executable) print("\nPython path:") for path in sys.path: print(f" - {path}") print("\nEnvironment variables:") print(f" PYTHONPATH: {os.environ.get('PYTHONPATH', 'Not set')}") print(f" VIRTUAL_ENV: {os.environ.get('VIRTUAL_ENV', 'Not set')}")
if __name__ == '__main__': print_paths()
复制代码


分别在激活虚拟环境前后运行这个脚本,你会发现关键的区别:

  1. sys.executable 指向了虚拟环境中的 Python 解释器

  2. sys.path 首先搜索虚拟环境的 site-packages

  3. VIRTUAL_ENV 环境变量被设置


包的导入机制


虚拟环境通过修改 sys.path 实现了包的隔离。当 Python 导入一个模块时,会按照以下顺序搜索:

  1. 当前目录

  2. PYTHONPATH 环境变量中的目录

  3. 标准库目录

  4. site-packages 目录


在虚拟环境中,这个搜索顺序被巧妙地修改了,使得虚拟环境的 site-packages 优先于系统的目录。


实现隔离的关键:符号链接


让我们看看虚拟环境中的 Python 解释器:


import osprint(os.path.realpath(sys.executable))
复制代码


你会发现它实际上是一个符号链接,指向系统的 Python 解释器。这就解释了为什么虚拟环境如此轻量:它复用了系统的 Python 解释器和标准库,只隔离了第三方包。


常见陷阱与解决方案


1. 路径相关问题


最常见的问题是找不到已安装的包。通常有两个原因:


# 检查当前 Python 环境import sysimport site
print(f"Python 版本: {sys.version}")print(f"Python 路径: {sys.executable}")print(f"site-packages: {site.getsitepackages()}")
复制代码


解决方案:

  • 确保虚拟环境已正确激活

  • 检查 PYTHONPATH 是否包含冲突路径


2. IDE 配置


以 VSCode 为例,正确配置虚拟环境:


  1. 打开命令面板(Ctrl+Shift+P)

  2. 输入 "Python: Select Interpreter"

  3. 选择虚拟环境的 Python 解释器


创建 .vscode/settings.json


{    "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",    "python.analysis.extraPaths": [        "${workspaceFolder}/src"    ]}
复制代码


高级应用


virtualenvwrapper:更友好的管理工具


虽然 venv 够用,但管理多个项目时可能不够方便。virtualenvwrapper 提供了更友好的命令:


# 安装pip install virtualenvwrapper
# Unix/macOS 配置(添加到 .bashrc 或 .zshrc)export WORKON_HOME=$HOME/.virtualenvsexport PROJECT_HOME=$HOME/projectssource /usr/local/bin/virtualenvwrapper.sh
复制代码


主要命令:


mkvirtualenv my_project  # 创建并激活环境workon my_project       # 切换环境deactivate             # 退出环境rmvirtualenv my_project # 删除环境
复制代码


现代化工具:pipenv 和 poetry


pipenv:结合了 pip 和 virtualenv


pipenv 使用 Pipfile 代替 requirements.txt,提供了更好的依赖锁定机制:


# 安装pip install pipenv
# 创建项目pipenv install
# 安装包pipenv install requests
# 进入环境pipenv shell
复制代码


Pipfile 示例:


[[source]]url = "https://pypi.org/simple"verify_ssl = truename = "pypi"
[packages]requests = "*"pandas = ">=1.3.0"
[dev-packages]pytest = "*"black = "*"
[requires]python_version = "3.8"
复制代码


poetry:更现代的依赖管理


poetry 提供了更完整的项目管理功能:


# 安装curl -sSL https://install.python-poetry.org | python3 -
# 创建新项目poetry new my_project
# 安装依赖poetry install
# 添加依赖poetry add requests
# 激活环境poetry shell
复制代码


pyproject.toml 示例:


[tool.poetry]name = "my_project"version = "0.1.0"description = ""authors = ["Your Name <your.email@example.com>"]
[tool.poetry.dependencies]python = "^3.8"requests = "^2.28.0"
[tool.poetry.dev-dependencies]pytest = "^7.1.0"
[build-system]requires = ["poetry-core>=1.0.0"]build-backend = "poetry.core.masonry.api"
复制代码


部署与生产环境


Docker 中的虚拟环境


在容器化部署时,虚拟环境仍然有用:


FROM python:3.8-slim
WORKDIR /app
# 创建虚拟环境RUN python -m venv /opt/venv# 使用虚拟环境ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
复制代码


CI/CD 配置


以 GitHub Actions 为例:


name: Python CI
on: [push]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.8' - name: Create venv run: | python -m venv .venv source .venv/bin/activate - name: Install dependencies run: | pip install -r requirements.txt - name: Run tests run: | pytest tests/
复制代码


最佳实践总结


1、项目结构推荐


my_project/├── .venv/├── src/│   └── my_project/│       ├── __init__.py│       └── main.py├── tests/├── .gitignore├── pyproject.toml  # 或 requirements.txt└── README.md
复制代码


2、环境管理建议

所有项目都使用虚拟环境

将 .venv 加入 .gitignore

使用 requirements.txt 或更现代的依赖管理工具

明确指定依赖版本


3、.gitignore 示例


# 虚拟环境.venv/venv/ENV/
# Python__pycache__/*.py[cod]*$py.class
# 包分发dist/build/*.egg-info/
复制代码


4、版本控制注意事项:锁定关键依赖版本定期更新依赖检查安全问题使用 pip-compile 或 poetry.lock 确保依赖可复现


结语


Python 虚拟环境是一个强大的工具,它不仅解决了依赖管理的问题,还为项目提供了良好的隔离性。从简单的 venv 到现代化的 poetry,工具在不断进化,但核心理念始终未变:为每个项目提供独立、可控、可复现的 Python 环境。


无论选择哪种方案,理解虚拟环境的工作原理都会帮助你更好地处理依赖管理问题,写出更可维护的 Python 项目。


文章转载自:Piper蛋窝

原文链接:https://www.cnblogs.com/piperliu/p/18646310

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Python 虚拟环境:原理解析与最佳实践_Python_不在线第一只蜗牛_InfoQ写作社区