1.2 uv 项目与依赖
前置:1.1 · 约 25 分钟 · 官方对应:uv 项目工作流、编写 pyproject.toml · 核对日期 2026-10-06(uv 0.11)
目标
- 说清
pyproject.toml、uv.lock、.venv、.python-version各自的职责。 - 掌握
uv sync/uv run/uv add/uv remove的使用场景。 - 能读懂一个项目的依赖声明,判断某个
import需要哪个包。
核心概念
四个文件/目录的分工
| 文件 | 职责 | 谁来改 | 对照 npm |
|---|---|---|---|
pyproject.toml | 项目元数据与直接依赖声明(PEP 621) | 人(或 uv add) | package.json |
uv.lock | 全部依赖(含间接依赖)的精确版本,保证可复现 | 只由 uv 生成 | package-lock.json |
.venv/ | 虚拟环境:项目专属的解释器链接 + 已安装包 | 只由 uv 生成,可随时删掉重建 | node_modules/ |
.python-version | 项目使用的 Python 版本 | uv python pin | .nvmrc |
本项目的 pyproject.toml:
toml
[project]
name = "jdp-python"
version = "0.1.0"
description = "Python 学习与实验仓(示例、学习文档)"
requires-python = ">=3.12"
dependencies = [
"anthropic>=1.11.0",
"python-dotenv>=1.2.4",
]注意:包名不一定等于导入名。安装 python-dotenv,代码里写 from dotenv import load_dotenv。
常用命令
| 场景 | 命令 |
|---|---|
按 uv.lock 创建/更新 .venv | uv sync |
| 在项目环境中运行脚本(运行前自动同步) | uv run examples/agent/minimal_agent.py |
| 进入项目环境的 REPL | uv run python |
添加依赖(同时改 pyproject.toml 与 uv.lock) | uv add httpx |
| 添加开发依赖 | uv add --dev pytest |
| 移除依赖 | uv remove httpx |
| 临时带一个包运行,不写入项目 | uv run --with rich python |
| 运行一次性命令行工具 | uvx ruff check .(等价 uv tool run) |
| 安装/固定 Python 版本 | uv python install 3.14 / uv python pin 3.14 |
依赖声明的版本说明符
pyproject.toml 中的版本约束遵循 版本说明符规范:
| 写法 | 含义 |
|---|---|
anthropic>=1.11.0 | 不低于 1.11.0 |
httpx>=0.27,<1 | 区间 |
rich~=13.7 | 兼容版本:>=13.7, ==13.* |
requests==2.32.3 | 精确版本(一般只在锁文件中出现) |
用代码读 pyproject.toml
pyproject.toml 是 TOML 格式。标准库 tomllib(3.11 起)可以解析它,得到普通的 dict:
Python · 可运行
python
import tomllib
text = """
[project]
name = "jdp-python"
requires-python = ">=3.12"
dependencies = ["anthropic>=1.11.0", "python-dotenv>=1.2.4"]
"""
data = tomllib.loads(text)
print(type(data))
print(data["project"]["name"])
for dep in data["project"]["dependencies"]:
print("依赖:", dep)单文件脚本的内联依赖
零散脚本可以把依赖写在文件头注释里(PEP 723 内联脚本元数据),uv run 脚本.py 会自动创建临时环境:
python
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///
import httpx
print(httpx.get("https://peps.python.org/").status_code)uv add --script 脚本.py httpx 可自动写入这段注释。
易错点
- 手改
uv.lock:不要。改依赖用uv add/uv remove,或改完pyproject.toml后执行uv lock。 - 用
pip install装进项目:绕过了 uv 的锁文件,下次uv sync会被移除。统一用uv add。 - 提交
.venv:它是生成物,已在.gitignore中忽略。 - 包名 ≠ 导入名:
python-dotenv→dotenv,pyyaml→yaml,beautifulsoup4→bs4。遇到ModuleNotFoundError先确认环境,再确认包名。
Python · 可运行演示报错
python
import pyyaml # 包名是 pyyaml,但导入名是 yaml:按包名导入必然失败对照
| 概念 | Python + uv | JS + npm | Java + Maven/Gradle |
|---|---|---|---|
| 依赖声明 | pyproject.toml | package.json | pom.xml / build.gradle |
| 锁文件 | uv.lock | package-lock.json | Gradle lockfile(可选) |
| 依赖安装位置 | 项目内 .venv/ | 项目内 node_modules/ | 全局 ~/.m2 缓存 |
| 运行项目命令 | uv run | npm run / npx | mvn exec:java |
| 包仓库 | PyPI | npm registry | Maven Central |
读代码
minimal_agent.py 的导入分三组(PEP 8 推荐顺序:标准库、第三方、本地):
python
import os # 标准库:随 Python 安装
import anthropic # 第三方:pyproject.toml 中的 anthropic
from dotenv import load_dotenv # 第三方:pyproject.toml 中的 python-dotenv判断一个导入来自哪里:标准库可在 标准库索引 中查到;查不到的去 pyproject.toml 找对应的包。
练习
练习 1:列出直接依赖的包名
实现 dependency_names(toml_text):解析 pyproject.toml 文本,返回 [project].dependencies 中每项的包名(去掉版本约束),保持原顺序。包名由字母、数字、-、_、. 组成,遇到第一个其他字符(如 >、=、<、~、[、空格)即结束。
练习
import tomllib
def dependency_names(toml_text):
...
快捷键:⌘/Ctrl + Enter 提交检查
练习 2:包名到导入名
IMPORT_NAMES 字典记录“包名 → 导入名”。补全它,使检查通过:python-dotenv、pyyaml、beautifulsoup4、anthropic 四个包。
练习
IMPORT_NAMES = {
"anthropic": "anthropic",
}
快捷键:⌘/Ctrl + Enter 提交检查
小结
pyproject.toml声明直接依赖,uv.lock锁定全部版本,.venv是可重建的安装目录。- 增删依赖用
uv add/uv remove,运行用uv run。 - 包名不等于导入名;
ModuleNotFoundError先查环境再查包名。