找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4644

积分

0

好友

605

主题
发表于 1 小时前 | 查看: 3| 回复: 0

Python Logo冬季主题装饰图

刚开始用 Python 并尝试创建自己的包时,我曾经很困惑——打包和依赖管理似乎比预想的复杂得多。况且市面上的工具实在太多,根本不知道哪一个才适合自己。相信不少人都有过同样的迷茫。这篇文章就来系统地梳理和对比一下 Python 生态里的环境与包管理工具,帮你看清每个工具的定位。

工具分类

我先把跟环境和包管理相关的功能分成五个类别:

  • Python 版本管理
  • 包管理
  • 环境管理(主要指虚拟环境)
  • 包构建
  • 包发布

下面的维恩图直观地展示了各类工具之间的交集,有些工具是单一用途的,有些则是“多面手”:

Python包管理工具分类维恩图

我们从开发者的视角挨个看这几个类别。假设你同时在做个人项目和工作项目:工作上要求使用 Python 3.7,个人项目却想用最新的 Python 3.11。换句话说,你需要能够安装不同的 Python 版本并在它们之间切换,这就涉及 Python 版本管理

项目里几乎总会用到第三方包,比如数据科学领域常用的 pandas、scikit‑learn。这些依赖必须安装和管理(升级等),这就是包管理要做的事情。

由于不同项目可能依赖同一个包的不同版本,我们需要创建和管理(虚拟)环境来避免依赖冲突。大多数工具使用虚拟环境,少数则使用被称为“本地包”(Local Packages)的概念,后面会聊到。

当你准备与他人共享代码时,首先要构建包,然后才能发布PyPI 或其他索引上。

接下来,我们逐一深入每个类别,并重点介绍其中最主要的工具。

Python 版本管理

定义

Python 版本管理工具能够让你方便地安装多个 Python 版本,并在它们之间自由切换。

为什么需要?

原因很多。例如你可能并行维护多个项目,而每个项目要求的 Python 版本不同;也可能你的库要兼容多个 Python 版本,需要在各版本下测试;又或者你只是想尝鲜新版本特性,甚至测试预发布版本。

工具

维恩图里涉及版本管理的有:pyenv、conda、rye 和 PyFlow。我们先看唯一的单一用途工具 pyenv,多用途工具稍后再说。

Python版本管理工具维恩图

Python 自带一个纯粹做版本管理的工具:pyenv,用起来相当简单。核心命令如下:

# 安装特定版本的 Python
pyenv install 3.10.4

# 在不同的 Python 版本之间切换

# 仅针对当前 shell 切换 Python 版本
pyenv shell <version>
# 在这个目录下,自动使用某个 Python 版本
pyenv local <version>
# 针对当前用户,全局设定 Python 版本
pyenv global <version>

(虚拟)环境管理

定义

环境管理工具可以创建和管理(虚拟)环境,让你为不同项目隔离依赖。

为什么需要?

前面说了,不同项目依赖不同的包版本,直接通过 pip install 把包安装到系统全局很容易引发冲突。虽然 --user 参数可以缓解,但很多初学者并不了解。因此,专业的虚拟环境管理工具就非常必要了。

工具

能够管理环境的工具有:venv、virtualenv、pipenv、conda、pdm、poetry、hatch、rye、PyFlow。其中只有 venv 和 virtualenv 是单一用途的,我们先看这两个。

环境管理工具维恩图(突出venv/virtualenv)

venv

venv 是 Python 内置的虚拟环境创建包。命令很直观:

# 创建一个新的环境
python3 -m venv <env_name>

# 激活环境
. <env_name>/bin/activate

# 退出环境
deactivate

virtualenv

virtualenv 是 venv 的增强版,功能更多、速度更快。常用命令与 venv 几乎一样:

# 创建新环境
virtualenv <env_name>

# 激活环境
. <env_name>/bin/activate

# 退出环境
deactivate

包管理

在聊包管理前,有必要先了解最重要的配置文件:pyproject.toml

pyproject.toml

Python 的打包机制经历了巨大改进。在 PEP 518 之前,主要依靠 setup.py 和 setuptools。如今,pyproject.toml 成了定义项目构建、元数据以及依赖等信息的标准文件。来看看 pandas 的 pyproject.toml 片段(完整文件见 github.com/pandas-dev/pandas):

[build-system]
# Minimum requirements for the build system to execute.
# See https://github.com/scipy/scipy/pull/12940 for the AIX issue.
requires = [
    "meson-python==0.13.1",
    "meson==1.2.1",
    "wheel",
    "Cython==3.0.5",  # Note: sync with setup.py, environment.yml and asv.conf.json
    # Any NumPy version should be fine for compiling.  Users are unlikely
    # to get a NumPy<1.25 so the result will be compatible with all relevant
    # NumPy versions (if not it is presumably compatible with their version).
    # Pin <2.0 for releases until tested against an RC.  But explicitly allow
    # testing the `.dev0` nightlies (which require the extra index).
    "numpy>1.22.4,<=2.0.0.dev0",
    "versioneer[toml]"
]

build-backend = "mesonpy"

[project]
name = 'pandas'
dynamic = [
  'version'
]
description = 'Powerful data structures for data analysis, time series, and statistics'
readme = 'README.md'
authors = [
  { name = 'The Pandas Development Team', email='pandas-dev@python.org' },
]
license = {file = 'LICENSE'}
requires-python = '>=3.9'
dependencies = [
  "numpy>=1.22.4; python_version<'3.11'",
  "numpy>=1.23.2; python_version=='3.11'",
  "numpy>=1.26.0; python_version>='3.12'",
  "python-dateutil>=2.8.2",
  "pytz>=2020.1",
  "tzdata>=2022.7"
]
classifiers = [
# 省略后续

.lock 文件

另一个打包关键文件是锁定文件(如 xxx.lock)。pyproject.toml 中包含的是抽象依赖声明,而锁定文件记录的是具体安装的确切版本(比如 pandas==2.0.3),这样可以保证项目在不同环境下的可重复构建。以下是 Poetry 生成的 poetry.lock 片段(原文件:github.com/python-poetry/poetry):

# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.

[[package]]
name = "build"
version = "1.0.3"
description = "A simple, correct Python build frontend"
optional = false
python-versions = ">= 3.7"
files = [
    {file = "build-1.0.3-py3-none-any.whl", hash = "sha256:589bf99a67df7c9cf07ec0ac0e5e2ea5d4b37ac63301c4986d1acb126aa83f8f"},
    {file = "build-1.0.3.tar.gz", hash = "sha256:538aab1b64f9828977f84bc63ae570b060a8ed1be419e7870b8b4fc5e6ea553b"},
]

[package.dependencies]
colorama = {version = "*", markers = "os_name == \"nt\""}
importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
packaging = ">=19.0"
pyproject_hooks = "*"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}

[package.extras]
docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"]
test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"]
typing = ["importlib-metadata (>=5.1)", "mypy (>=1.5.0,<1.6.0)", "tomli", "typing-extensions (>=3.7.4.3)"]
virtualenv = ["virtualenv (>=20.0.35)"]

定义

包管理工具负责下载、安装项目依赖的库,并解决依赖关系。

动机

包(package)让我们可以通过 from package.module import my_function 这样的语法来组织代码,也方便共享。每个包在 pyproject.toml 中声明了自己的依赖,其他人只需通过这个文件就能一次性安装所有需要的包。

工具

能做包管理的工具不少:pip、pipx、pipenv、conda、pdm、poetry、rye、PyFlow。其中 pip 是 Python 开发生态中几乎人人会用的标准包管理器。

包管理工具维恩图(突出pip)

pip 随 Python 发行版一起提供,可以从 PyPI 和其他索引安装包。最熟悉的命令或许就是 pip install <package_name> 了。

多用途工具

下面重点介绍那些跨多个类别的工具。

pipenv

光看名字就知道,pipenv 把 pip 和 virtualenv 结合了起来。它可以同时完成虚拟环境管理和包管理:

维恩图:突出pipenv

pipenv 引入了两个额外文件:

  • Pipfile:一个 toml 文件,类似 pyproject.toml,用于声明项目的依赖。
  • Pipfile.lock:锁定文件,保证确定性构建,不再需要手动维护 requirements.txt

常用命令:

# 安装某个包
pipenv install <package_name>

# 在虚拟环境运行某个脚本
pipenv run <script_name.py>

# 激活虚拟环境
pipenv shell

Conda

Conda 是一个通用的包管理系统,不限于 Python 包。功能庞大,这里不展开,网上教程很多。唯一要提的是,虽然 Conda 也能构建和发布包,但它生成的是 Conda 包,与我们通常的 PyPI 包稍有不同,所以我没把它列入标准的包构建/发布类别。

维恩图:突出Conda

特征评估

接下来我会从以下几个维度比较这些工具:

  • 是否管理依赖?
  • 是否解析/锁定依赖?
  • 是否有干净的构建/发布流程?
  • 是否支持插件?
  • 是否支持 PEP 660(可编辑安装)?PEP 660 基于 pyproject.toml 的可编辑安装,开发库时很有用。
  • 是否支持 PEP 621(项目元数据)?PEP 621 定义了如何在 pyproject.toml 中书写核心元数据。之所以加这个维度,是因为有个工具(稍后揭晓)目前还不支持该 PEP,而是自己另搞一套。

Flit

Flit 专注一件事:把纯 Python 包发布到 PyPI,不关心其他事情:

  • Python 版本管理:❌
  • 包管理:❌
  • 环境管理:❌
  • 构建包:✅
  • 发布包:✅

维恩图里它只落在包构建和发布的重叠区域:

维恩图:突出Flit

  • 管理依赖?❌
  • 解析/锁定依赖?❌
  • 构建/发布流程?✅
  • 允许插件?❌
  • PEP 660?✅
  • PEP 621?✅

核心命令:

# 创建新的 pyproject.toml
flit init

# 构建并发布
flit publish

Poetry

Poetry 是人气很高的工具。维恩图显示,除了 Python 版本管理之外,它几乎包揽一切:

  • Python 版本管理:❌
  • 包管理:✅
  • 环境管理:✅
  • 构建包:✅
  • 发布包:✅

维恩图:突出Poetry

需要注意的是,Poetry 目前还不支持 PEP 621。GitHub 上的相关 issue 已经开了大约一年半,依然没有解决(github.com/python-poetry/poetry/issues/3332)。

  • 管理依赖?✅
  • 解析/锁定依赖?✅
  • 构建/发布流程?✅
  • 允许插件?✅
  • PEP 660?✅
  • PEP 621?❌

创建项目

# 创建目录结构和 pyproject.toml
poetry new <project_name>

# 交互式创建 pyproject.toml
poetry init

# 从 pyproject.toml 安装依赖
poetry install

依赖管理

# 添加依赖
poetry add <package_name>

# 显示所有依赖
poetry show --tree

# 激活虚拟环境
poetry shell

# 在虚拟环境运行脚本
poetry run python <script_name.py>

锁定文件
首次安装包时,Poetry 解析 pyproject.toml 中的依赖并下载最新版本,随后将所有包的确切版本写入 poetry.lock。建议把该文件提交到版本仓库,保证团队一致。升级依赖用:

poetry update

构建/发布

# 打包(生成 .tar.gz 和 .whl)
poetry build

# 发布到 PyPI
poetry publish

pdm

pdm 是一个相对较新的包和依赖管理器(始于 2019 年),受到 Poetry 和 PyFlow 的启发(PyFlow 已不再活跃,所以本文不深入)。它要求 Python 3.7+,一个显著区别是允许用户自行选择构建后端。此外,pdm 是除 PyFlow 外唯一实现了 PEP 582(本地包)的工具,不过该 PEP 最近已被拒绝。

维恩图上,pdm 紧挨着 Poetry,功能上也是除版本管理外全覆盖:

维恩图:突出pdm

  • Python 版本管理:❌

  • 包管理:✅

  • 环境管理:✅

  • 构建包:✅

  • 发布包:✅

  • 管理依赖?✅

  • 解析/锁定依赖?✅

  • 构建/发布流程?✅

  • 允许插件?✅

  • PEP 660?✅

  • PEP 621?✅

创建项目

# 交互式创建 pyproject.toml
pdm init

# 从 pyproject.toml 安装包
pdm install

依赖管理

# 添加依赖
pdm add <package_name>

# 展示所有依赖
pdm list --graph

运行代码
没有 shell 命令,但可以直接用 run

# 使用当前环境运行
pdm run python <script_name.py>

锁定文件
与 Poetry 类似,首次安装后生成 pdm.lock。更新依赖:

pdm update

构建/发布

# 打包
pdm build

# 发布到 PyPI
pdm publish

Hatch

Hatch 的特点:

  • Python 版本管理:❌
  • 包管理:❌
  • 环境管理:✅
  • 构建包:✅
  • 发布包:✅

它的作者曾承诺会尽快加入锁定功能(github.com/pypa/hatch/issues/1030),建议留意最新版本是否已经实现。

维恩图:突出Hatch

  • 管理依赖?❌
  • 解析/锁定依赖?❌
  • 构建/发布流程?✅
  • 允许插件?✅
  • PEP 660?✅
  • PEP 621?✅

创建项目

# 创建目录结构及 pyproject.toml
hatch new <project_name>

# 交互式创建项目
hatch new -i <project_name>

# 初始化现有项目或创建 pyproject.toml
hatch new --init

依赖管理
没有 add 命令,依赖需要手动添加到 pyproject.toml。查看依赖用:

hatch dep show table

运行代码

# 激活虚拟环境
hatch shell

# 在虚拟环境运行脚本
hatch run python <script_name.py>

构建/发布

# 打包
hatch build

# 发布到 PyPI
hatch publish

声明式环境管理
Hatch 的一个独特功能是允许在 pyproject.toml 里直接配置虚拟环境,甚至为环境定义专属脚本,例如用于代码格式化(更多见官方文档)。

Rye

Rye 由 Flask 作者 Armin Ronacher 于 2023 年 5 月推出,设计上深受 Rust 的 rustup 和 cargo 的影响。它用 Rust 编写,覆盖了所有五个类别:

维恩图:Rye全覆盖

  • Python 版本管理:✅

  • 包管理:✅

  • 环境管理:✅

  • 构建包:✅

  • 发布包:✅

  • 管理依赖?✅

  • 解析/锁定依赖?✅

  • 构建/发布流程?✅

  • 允许插件?❌(未来可能添加)

  • PEP 660?✅

  • PEP 621?✅

创建项目

# 创建目录结构和 pyproject.toml
rye init <project_name>

# 指定 Python 版本
rye pin 3.10

依赖管理

# 添加依赖(尚未安装)
rye add <package_name>

# 同步虚拟环境、锁定文件等(此步骤安装依赖)
rye sync

运行代码

# 启动虚拟环境
rye shell

# 使用虚拟环境运行脚本
rye run python <script_name.py>

构建/发布

# 打包
rye build

# 发布到 PyPI
rye publish

总结

各工具的特征对比汇总如下:

工具 管理依赖 解析/锁定依赖 构建/发布流程 插件支持 PEP 660 PEP 621
Flit
Poetry
pdm
Hatch
rye

原文:https://alpopkes.com/posts/python/packaging_tools
译文:https://juejin.cn/post/7325611798135767090
译者:hashcon

如果你对 Python 工具选型仍有困惑,欢迎到 云栈社区 一起探讨。也别忘了查看 Python 官方文档里的更多细节,关于 Conda 的使用还可以参考官方的入门指南。




上一篇:UV 迁移实录:1 小时搬 5 个项目,CI 管道从 9 分钟压到 12 秒
下一篇:PicoLM:80KB纯C程序,让10美元开发板运行十亿参数大模型
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-7 04:34 , Processed in 1.119004 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表