foril@blog ~
  __            _ _ 
 / _| ___  _ __(_) |
| |_ / _ \| '__| | |
|  _| (_) | |  | | |
|_|  \___/|_|  |_|_|
// developer & blogger
💻theme: auto
[░░░░░░░░░░░░░░░░░░░░] 0%

Python 项目管理

📅 2024-11-23|⏱ ~6 min read|#学习笔记

Python 的项目管理一直给人一种“工具很多,但总差一点统一感”的感觉。写一个小脚本时,pip install 好像就够了;项目稍微复杂一点,就会开始遇到 Python 版本、虚拟环境、运行依赖、开发依赖、构建配置、锁文件这些问题。再往深度学习或者科学计算方向走,还会碰到 CUDA、C/C++ 库、系统依赖这些不完全属于 Python 的东西。

这篇文章不打算整理一个完整工具大全,只是简单记录一下 Python 项目管理的历史脉络,以及现在比较常见的几类工具应该如何理解。

##为什么会显得有点乱

Python 早期更多是作为脚本语言被使用,项目形态不像今天这样复杂。后来生态不断扩大,包分发、虚拟环境、构建系统、依赖锁定等需求逐渐出现,于是工具也像“补丁”一样一层层长出来。

比较典型的分工是:

  • pip 负责安装包
  • venv 负责创建虚拟环境
  • requirements.txt 记录一组依赖
  • setup.py / setup.cfg 负责打包和构建配置
  • 后来逐渐引入 pyproject.toml 作为统一配置入口

这些工具本身都能解决问题,但组合起来以后,新手很容易困惑:到底应该把依赖写在哪里?虚拟环境要不要提交?开发依赖和运行依赖怎么分?部署时怎样保证别人安装到同一批版本?

##官方基线:venv、pip 和 pyproject.toml

先看官方和 PyPA 体系下的基础工具。

venv 是 Python 标准库提供的虚拟环境工具。它的作用是给项目创建一个隔离目录,里面有自己的 Python 解释器入口和 site-packages,避免不同项目之间的依赖互相污染。

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

.venv 通常放在项目目录里,但不提交到 Git。虚拟环境应该被看作可以随时删除并重建的产物,真正需要提交的是依赖声明文件。

pip 则是最基础的包安装工具:

sh
python -m pip install requests python -m pip install -r requirements.txt

pyproject.toml 是现代 Python 项目越来越核心的配置入口。它可以用来声明构建系统、项目元信息、运行依赖,也可以放一些开发工具的配置,例如 pytestruffblack 等。

一个很简化的例子:

toml
[project] name = "example" version = "0.1.0" requires-python = ">=3.11" dependencies = [ "requests>=2.32.0", ] [dependency-groups] dev = [ "pytest>=8.0.0", "ruff>=0.8.0", ]

可以粗略理解为:venv 管环境,pip 装包,pyproject.toml 描述项目。它们构成了现代 Python 项目管理的基础。

##Conda:另一套独立生态

Conda 不是 Python 官方项目管理工具,但它在数据科学、深度学习、科学计算里非常常见。

它和 venv + pip 最大的区别在于:Conda 管理的不只是 Python 包,还可以管理 Python 解释器本身,以及 C/C++ 库、CUDA、R、命令行工具等非 Python 依赖。对于 NumPy、PyTorch、CUDA 这类带有复杂二进制依赖的场景,Conda 往往能减少不少环境配置上的麻烦。

常见用法类似这样:

sh
conda create -n demo python=3.11 conda activate demo conda install numpy

如果项目非常依赖底层二进制环境,Conda 依然是一个很实用的选择。但它和 PyPI / PyPA 体系是两套生态:Conda 有自己的 channel、包格式和依赖解析方式。在一个环境里混用 conda installpip install 也不是不行,只是最好先用 Conda 安装重型依赖,再用 pip 补充 Conda 中没有的 Python 包,避免依赖解析互相打架。

##uv:把零散流程收起来

近几年比较流行的一个工具是 uv。它由 Rust 编写,定位是高速 Python 包和项目管理器。和只把它理解成“更快的 pip”相比,我觉得更准确的说法是:uv 试图把建环境、装依赖、写配置、生成锁文件、运行命令这些流程收进同一个工具里

一个新项目可以这样开始:

sh
uv init demo cd demo uv add requests uv add --dev pytest ruff uv run python main.py

执行这些命令后,uv 会维护 pyproject.toml,并生成 uv.lock 来锁定依赖版本。之后其他人拿到项目时,可以通过:

sh
uv sync

把环境同步到锁文件描述的状态。

需要注意的是,uv.lock 应该通过 uv lockuv syncuv runuv add 这类项目命令生成和更新。uv pip compile 更像是兼容 pip-tools 的用法,通常用于把依赖编译成 requirements.txt 这类文件,而不是生成 uv.lock

sh
uv lock uv sync # requirements 风格的锁定输出 uv pip compile pyproject.toml -o requirements.txt

如果是新项目,我现在会更倾向于直接用 uv init / uv add / uv sync 这条项目工作流;如果是老项目,还在用 requirements.txt,则可以先用 uv pip install -r requirements.txtuv pip compile 逐步迁移。

##一个简单选择

如果只是普通 Python 项目,可以先考虑:

  • pyproject.toml 记录项目元信息和依赖
  • .venv 隔离环境
  • uv 管理依赖、锁文件和运行命令

如果是深度学习、科学计算,或者项目明显依赖 CUDA、系统库、跨语言包,那么 Conda 依然值得考虑。

也就是说,Python 项目管理并没有一个绝对统一的答案。更现实的理解是:官方标准在逐渐收敛到 pyproject.toml,社区工具则在尝试把分散的流程变得更顺手。对个人项目来说,先把“依赖写清楚、环境可重建、版本能锁住”做好,就已经能避免很多后续麻烦。

##参考

$ tree --headings