Python 包管理工具
Python 生态中主流的包管理工具有 uv 和 Poetry。uv 是基于 Rust 开发的现代工具,速度极快,正逐渐成为主流首选;Poetry 是功能完善的传统选项,项目管理能力强。两者都以 pyproject.toml 作为项目配置文件。 相关文档:装饰器与函数高级(/python-zhuang-shi-qi-yu-han-shu-gao-ji-yong-fa/) | FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) uv 是 Astral(Ruff 的开发团队)推出的 Python 包管理器和项目管理工具,用 Rus
官方文档:https://docs.astral.sh/uv/
适用版本:uv 0.4+(2026-05-07 核实)
Python 生态中主流的包管理工具有 uv 和 Poetry。uv 是基于 Rust 开发的现代工具,速度极快,正逐渐成为主流首选;Poetry 是功能完善的传统选项,项目管理能力强。两者都以 pyproject.toml 作为项目配置文件。
相关文档:装饰器与函数高级 | FastAPI完全指南
uv
uv 是 Astral(Ruff 的开发团队)推出的 Python 包管理器和项目管理工具,用 Rust 编写。相比 pip,安装速度快 10-100 倍,且集成了虚拟环境管理、Python 版本管理等功能。
安装 uv
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows(PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 通过 pip 安装
pip install uv
# 验证安装
uv --version
项目初始化
uv init
在当前目录或指定目录初始化新项目,创建 pyproject.toml、README.md 和基础目录结构。
uv init [OPTIONS] [PATH]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PATH | str | 当前目录 | 项目目录路径 |
| --name | str | 目录名 | 项目名称 |
| --python | str | 系统 Python | 指定 Python 版本,如 3.12 |
| --package | flag | 关闭 | 初始化为可分发包(含 src 布局) |
| --app | flag | 开启 | 初始化为应用(默认行为) |
| --lib | flag | 关闭 | 初始化为库(含 __init__.py) |
| --no-readme | flag | 关闭 | 不生成 README.md |
| --vcs | str | git | 版本控制系统,none 可禁用 |
# 创建新应用项目
uv init my-project
cd my-project
# 创建库项目
uv init --lib my-library
# 指定 Python 版本
uv init --python 3.12 my-project
# 生成的目录结构(应用模式)
# my-project/
# ├── .python-version # Python 版本锁定文件
# ├── .gitignore
# ├── README.md
# ├── hello.py # 示例脚本
# └── pyproject.toml
依赖管理
uv add
添加依赖并自动更新 pyproject.toml 和 uv.lock。
uv add [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 包名,支持版本约束,如 requests>=2.28 |
| --dev / -d | flag | 关闭 | 添加为开发依赖 |
| --optional | str | - | 添加为可选依赖组,如 --optional test |
| --python | str | - | 指定目标 Python 版本 |
| --editable / -e | flag | 关闭 | 以可编辑模式安装本地包 |
| --index | str | PyPI | 指定包索引 URL |
| --no-sync | flag | 关闭 | 只修改 pyproject.toml,不安装 |
# 添加生产依赖
uv add requests
uv add "fastapi>=0.100.0"
uv add "sqlalchemy[asyncio]"
# 添加多个依赖
uv add requests httpx aiohttp
# 添加开发依赖
uv add --dev pytest ruff mypy
# 添加可选依赖
uv add --optional docs mkdocs mkdocs-material
# 添加本地可编辑包
uv add --editable ../my-local-package
# 从私有仓库安装
uv add --index https://my.private.repo/simple/ my-private-package
uv remove
移除依赖并更新配置文件。
uv remove [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 要移除的包名 |
| --dev | flag | 关闭 | 从开发依赖中移除 |
| --optional | str | - | 从指定可选依赖组移除 |
uv remove requests
uv remove --dev pytest
uv sync
将虚拟环境与 uv.lock 同步,确保环境与锁定文件完全一致。
uv sync [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --frozen | flag | 关闭 | 不更新 uv.lock,仅按现有锁定文件安装 |
| --no-dev | flag | 关闭 | 不安装开发依赖 |
| --extra | str | - | 安装指定可选依赖组 |
| --all-extras | flag | 关闭 | 安装所有可选依赖 |
| --python | str | - | 指定 Python 版本 |
# 同步所有依赖(包括开发依赖)
uv sync
# 仅同步生产依赖(适合部署)
uv sync --no-dev
# 同步并安装指定可选依赖
uv sync --extra docs --extra test
# CI 环境:不更新锁定文件
uv sync --frozen
uv run
在项目的虚拟环境中运行命令,无需手动激活虚拟环境。
uv run [OPTIONS] <COMMAND> [ARGS]...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| COMMAND | str | 必填 | 要运行的命令 |
| --with | str | - | 临时安装额外包(不写入 pyproject.toml) |
| --python | str | - | 指定 Python 版本 |
| --no-sync | flag | 关闭 | 不自动同步依赖 |
# 运行 Python 脚本
uv run python main.py
# 运行项目工具
uv run pytest
uv run ruff check .
uv run mypy src/
# 临时安装包并运行(不污染项目依赖)
uv run --with rich python -c "import rich; rich.print('[bold]Hello[/bold]')"
# 运行 Python 交互式解释器
uv run python
uv venv
创建和管理虚拟环境。
uv venv [OPTIONS] [PATH]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PATH | str | .venv |
虚拟环境路径 |
| --python / -p | str | 系统 Python | 指定 Python 版本 |
| --seed | flag | 关闭 | 预安装 pip、setuptools、wheel |
| --system-site-packages | flag | 关闭 | 允许访问系统级包 |
# 在默认位置创建虚拟环境
uv venv
# 指定 Python 版本
uv venv --python 3.12
# 指定路径
uv venv /path/to/myenv
# 激活(Linux/macOS)
source .venv/bin/activate
# 激活(Windows)
.venv\Scripts\activate
uv tool install
在隔离环境中全局安装命令行工具,工具会添加到 PATH 中,但不污染任何项目环境。
uv tool install [OPTIONS] <PACKAGE>
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGE | str | 必填 | 要安装的工具包名 |
| --python | str | - | 指定工具运行的 Python 版本 |
| --with | str | - | 同时安装额外包(如插件) |
| --force | flag | 关闭 | 强制重新安装 |
# 安装常用工具
uv tool install ruff
uv tool install mypy
uv tool install black
uv tool install cookiecutter
# 安装带插件的工具
uv tool install mkdocs --with mkdocs-material
# 列出已安装的工具
uv tool list
# 卸载工具
uv tool uninstall ruff
# 更新工具
uv tool upgrade ruff
pyproject.toml 配置结构(uv)
[project]
name = "my-project"
version = "0.1.0"
description = "A sample project"
readme = "README.md"
requires-python = ">=3.11"
license = { text = "MIT" }
authors = [
{ name = "Alice", email = "[email protected]" }
]
dependencies = [
"fastapi>=0.100.0",
"sqlalchemy[asyncio]>=2.0",
"pydantic>=2.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"ruff>=0.1.0",
"mypy>=1.0",
]
docs = [
"mkdocs>=1.5",
"mkdocs-material>=9.0",
]
[project.scripts]
my-cli = "my_project.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
dev-dependencies = [
"pytest>=7.0",
"ruff>=0.1.0",
]
[tool.uv.sources]
# 指定包的来源
my-local-pkg = { path = "../my-local-pkg", editable = true }
my-git-pkg = { git = "https://github.com/user/repo", branch = "main" }
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.mypy]
python_version = "3.11"
strict = true
Poetry
Poetry 是功能完善的 Python 依赖管理和打包工具,以 pyproject.toml 为核心,提供依赖解析、虚拟环境管理和包发布功能。
安装 Poetry
# 官方安装脚本(推荐,独立安装不依赖项目 Python)
curl -sSL https://install.python-poetry.org | python3 -
# Windows(PowerShell)
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python -
# 验证安装
poetry --version
# 配置(可选):将虚拟环境创建在项目目录内
poetry config virtualenvs.in-project true
项目初始化
poetry new
创建新项目,包含标准目录结构。
poetry new [OPTIONS] <NAME>
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| NAME | str | 必填 | 项目名称 |
| --src | flag | 关闭 | 使用 src 布局(推荐库项目) |
| --name | str | NAME | 包名(与目录名不同时使用) |
# 创建应用项目
poetry new my-project
# 生成的目录结构
# my-project/
# ├── my_project/
# │ └── __init__.py
# ├── tests/
# │ └── __init__.py
# ├── README.md
# └── pyproject.toml
# 使用 src 布局(库项目推荐)
poetry new --src my-library
# my-library/
# ├── src/
# │ └── my_library/
# │ └── __init__.py
# ├── tests/
# ├── README.md
# └── pyproject.toml
poetry init
在已有目录中交互式初始化 pyproject.toml,适合为现有项目添加 Poetry 支持。
poetry init [OPTIONS]
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| --name | str | 目录名 | 项目名 |
| --dependency | str | - | 预先指定依赖,如 requests:^2.28 |
| --dev-dependency | str | - | 预先指定开发依赖 |
| --no-interaction | flag | 关闭 | 非交互模式,使用默认值 |
# 交互式初始化
poetry init
# 非交互式(CI 环境)
poetry init --no-interaction
依赖管理
poetry add
添加依赖,更新 pyproject.toml 和 poetry.lock。
poetry add [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 包名,支持版本约束 |
| --group / -G | str | main | 依赖组名,dev 为开发依赖 |
| --editable / -e | flag | 关闭 | 可编辑安装(本地包) |
| --extras / -E | str | - | 安装指定 extras |
| --python | str | - | 限制 Python 版本约束 |
| --source | str | - | 指定包来源名称 |
| --dry-run | flag | 关闭 | 模拟运行,不实际安装 |
# 添加生产依赖
poetry add requests
poetry add "fastapi>=0.100.0"
poetry add "sqlalchemy[asyncio]"
# 添加开发依赖(推荐方式)
poetry add --group dev pytest
poetry add -G dev ruff mypy pytest-asyncio
# 添加本地可编辑包
poetry add --editable ../my-local-package
# 添加 Git 依赖
poetry add "git+https://github.com/user/repo.git"
# 版本约束语法
# ^1.2.0 -> >=1.2.0 <2.0.0(语义化版本,默认)
# ~1.2.0 -> >=1.2.0 <1.3.0
# >=1.2.0 -> 最低版本限制
# * -> 任意版本
poetry remove
移除依赖。
poetry remove [OPTIONS] <PACKAGES>...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | 必填 | 包名 |
| --group / -G | str | main | 从指定依赖组移除 |
poetry remove requests
poetry remove --group dev pytest
poetry update
更新依赖到 pyproject.toml 约束范围内的最新版本,并更新 poetry.lock。
poetry update [OPTIONS] [PACKAGES]...
| 参数/选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| PACKAGES | str | - | 指定更新的包,省略则更新所有 |
| --dry-run | flag | 关闭 | 模拟运行 |
| --no-dev | flag | 关闭 | 不更新开发依赖 |
# 更新所有依赖
poetry update
# 只更新指定包
poetry update requests fastapi
pyproject.toml 与 poetry.lock
pyproject.toml:声明式依赖配置,由开发者手动维护,指定版本约束范围。提交到版本控制。
poetry.lock:精确锁定所有依赖(含传递依赖)的具体版本,由 Poetry 自动生成。必须提交到版本控制,确保团队环境一致。
# 根据 pyproject.toml 安装(首次,生成 poetry.lock)
poetry install
# 根据 poetry.lock 安装(CI/生产,不更新锁定文件)
poetry install --frozen # Poetry 1.7+
# 或
poetry install --no-update
# 仅安装生产依赖
poetry install --only main
# 安装指定组
poetry install --with docs,test
常用运行命令
# 在虚拟环境中运行命令
poetry run python main.py
poetry run pytest
poetry run ruff check .
# 激活虚拟环境
poetry shell # 创建子 shell(Poetry 1.x)
# 查看虚拟环境信息
poetry env info
poetry env list
# 手动指定 Python 版本
poetry env use python3.12
poetry build 和 poetry publish
# 构建分发包(wheel 和 sdist)
poetry build
# 输出到 dist/ 目录
# dist/
# ├── my_project-0.1.0-py3-none-any.whl
# └── my_project-0.1.0.tar.gz
# 构建指定格式
poetry build --format wheel
poetry build --format sdist
# 发布到 PyPI
poetry publish
# 发布到私有仓库
poetry publish --repository my-repo
# 先构建再发布
poetry publish --build
# 配置 PyPI 凭证
poetry config pypi-token.pypi <your-token>
# 添加私有仓库
poetry source add my-repo https://my.private.repo/simple/
poetry config http-basic.my-repo username password
uv 与 Poetry 对比
| 特性 | uv | Poetry |
|---|---|---|
| 安装速度 | 极快(Rust 实现,10-100x) | 较慢(Python 实现) |
| Python 版本管理 | 内置(uv python install) |
需配合 pyenv |
| 锁定文件 | uv.lock |
poetry.lock |
| 与 pip 兼容性 | 高(uv pip 子命令) | 中(需特定格式) |
| 发布工具 | 需配合 twine 或其他工具 | 内置 poetry publish |
| 成熟度 | 新兴,快速迭代 | 成熟,生态完善 |
| 推荐场景 | 新项目、速度优先 | 需要发布到 PyPI 的库 |
pyproject.toml 完整结构参考
[project] 元数据字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | str | 是 | 包名(PyPI 唯一标识) |
| version | str | 是 | 版本号,遵循 PEP 440 |
| description | str | 否 | 一行描述 |
| readme | str | 否 | README 文件路径(README.md) |
| requires-python | str | 否 | Python 版本约束(>=3.11) |
| license | str/table | 否 | 许可证,如 {text="MIT"} 或 {file="LICENSE"} |
| authors | list | 否 | 作者列表,每项含 name 和/或 email |
| maintainers | list | 否 | 维护者列表 |
| keywords | list | 否 | 搜索关键词 |
| classifiers | list | 否 | PyPI 分类器列表 |
| urls | table | 否 | 项目链接,如 {Homepage="...", Repository="..."} |
| dependencies | list | 否 | 生产依赖列表 |
| optional-dependencies | table | 否 | 可选依赖组 |
| scripts | table | 否 | 命令行入口点 |
| entry-points | table | 否 | 插件入口点 |
| dynamic | list | 否 | 由构建后端动态生成的字段列表 |
[project]
name = "my-awesome-lib"
version = "1.2.3"
description = "An awesome Python library"
readme = "README.md"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [
{ name = "Alice Smith", email = "[email protected]" }
]
keywords = ["async", "web", "api"]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"License :: OSI Approved :: MIT License",
"Intended Audience :: Developers",
]
urls = { Homepage = "https://github.com/alice/my-lib", Documentation = "https://docs.example.com" }
dependencies = [
"httpx>=0.24.0",
"pydantic>=2.0",
]
[project.dependencies] 与 [project.optional-dependencies]
# 生产依赖(标准格式)
[project]
dependencies = [
"requests>=2.28.0",
"fastapi>=0.100.0,<1.0.0",
"sqlalchemy[asyncio]>=2.0",
'tomli>=1.1.0; python_version < "3.11"', # 条件依赖
]
# 可选依赖组
[project.optional-dependencies]
test = [
"pytest>=7.0",
"pytest-asyncio>=0.21",
"httpx>=0.24.0",
]
docs = [
"mkdocs>=1.5",
"mkdocs-material>=9.0",
]
dev = [
"my-awesome-lib[test,docs]", # 组合多个可选组
"ruff>=0.1.0",
"mypy>=1.0",
]
# 安装方式
# pip install my-awesome-lib[test]
# uv add "my-awesome-lib[test,docs]"
[tool.uv] 配置
[tool.uv]
# 开发依赖(uv 专属,不在 [project.optional-dependencies] 中)
dev-dependencies = [
"pytest>=7.0",
"ruff>=0.1.0",
]
# Python 版本约束
python-version = ">=3.11"
# 包来源
[tool.uv.sources]
local-pkg = { path = "../local-pkg", editable = true }
git-pkg = { git = "https://github.com/user/repo.git", branch = "main" }
# 私有仓库
tool.uv.index
name = "private"
url = "https://my.private.repo/simple/"
[tool.poetry] 配置
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "A Poetry project"
authors = ["Alice <[email protected]>"]
readme = "README.md"
packages = [{ include = "my_project", from = "src" }]
[tool.poetry.dependencies]
python = "^3.11"
fastapi = "^0.100.0"
sqlalchemy = { version = "^2.0", extras = ["asyncio"] }
requests = { version = "^2.28", optional = true }
[tool.poetry.group.dev.dependencies]
pytest = "^7.0"
ruff = "^0.1.0"
mypy = "^1.0"
[tool.poetry.group.docs.dependencies]
mkdocs = "^1.5"
mkdocs-material = "^9.0"
[tool.poetry.extras]
http = ["requests"]
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
虚拟环境管理
venv(标准库)
Python 内置模块,无需安装额外工具。
# 创建虚拟环境
python -m venv .venv
# 创建时包含系统级包
python -m venv --system-site-packages .venv
# 激活(Linux/macOS)
source .venv/bin/activate
# 激活(Windows CMD)
.venv\Scripts\activate.bat
# 激活(Windows PowerShell)
.venv\Scripts\Activate.ps1
# 退出虚拟环境
deactivate
# 删除虚拟环境(直接删除目录)
rm -rf .venv
# 在脚本中检测是否处于虚拟环境
import sys
def in_virtualenv():
return sys.prefix != sys.base_prefix
print(in_virtualenv()) # True 表示在虚拟环境中
.python-version 文件
.python-version 是纯文本文件,内容为 Python 版本号,被 pyenv 和 uv 等工具读取以自动选择 Python 版本。
# 内容示例
3.12.2
# uv 自动创建
uv init --python 3.12 # 自动生成 .python-version
# 手动创建
echo "3.12.2" > .python-version
# uv 根据 .python-version 自动选择解释器
# pyenv 根据 .python-version 自动切换版本
踩坑与注意事项
1. 依赖解析冲突
当多个包要求同一依赖的不相容版本时,会发生解析冲突。
# 场景:package-a 要求 requests>=2.28, package-b 要求 requests<2.0
# uv 报错示例:
# error: No solution found when resolving dependencies:
# Because package-a requires requests>=2.28 and package-b requires requests<2.0,
# we can conclude that package-a and package-b cannot be used together.
# 诊断方法
uv pip compile pyproject.toml --verbose # 查看详细解析过程
poetry why requests # 查看为何安装某包
# 解决方案 1:放宽版本约束(如果安全的话)
# 解决方案 2:使用 override(uv)或 override(Poetry)强制指定版本
# 解决方案 3:寻找替代包
# uv 强制覆盖版本
[tool.uv]
override-dependencies = [
"requests==2.31.0",
]
# Poetry 覆盖
[tool.poetry.dependencies]
requests = { version = "2.31.0", override = true } # 实验性功能
2. editable install 的常见问题
# 问题:editable 包修改后不生效
# 原因:Python 解释器缓存了旧的 .pyc 文件,或工具未正确设置 pth 文件
# 解决方案:确认 editable 安装正确
pip show -f my-package # 检查安装方式
# 应看到类似:Location: /path/to/src
# uv editable 安装
uv add --editable ./my-local-pkg
# 手动验证
python -c "import my_package; print(my_package.__file__)"
# 应指向源码目录,而非 site-packages
# 重新安装(如果不生效)
uv remove my-local-pkg && uv add --editable ./my-local-pkg
3. 私有仓库配置
# uv 配置私有仓库
# 方法 1:在 pyproject.toml 中声明
tool.uv.index
name = "private"
url = "https://private.repo/simple/"
# 认证通过环境变量
# UV_INDEX_PRIVATE_USERNAME=user
# UV_INDEX_PRIVATE_PASSWORD=password
# 方法 2:使用 .netrc 文件(~/.netrc)
# machine private.repo
# login username
# password mypassword
# Poetry 配置私有仓库
poetry source add private https://private.repo/simple/
poetry config http-basic.private username password
# 或使用 token
poetry config pypi-token.private <token>
# 注意:不要将密码写入 pyproject.toml 或提交到版本控制
# 使用环境变量传递敏感信息
export POETRY_HTTP_BASIC_PRIVATE_PASSWORD=mypassword
4. uv.lock / poetry.lock 的版本控制策略
# 锁定文件必须提交到版本控制(库和应用均适用)
# 原因:确保所有开发者、CI、生产环境使用完全相同的依赖版本
# .gitignore 不应包含锁定文件
# 错误示例(不要这样做):
# uv.lock
# poetry.lock
# CI 中使用锁定文件安装(不更新)
uv sync --frozen
poetry install --frozen # Poetry 1.7+
5. Python 版本与虚拟环境不匹配
# 问题:项目要求 Python 3.12,但系统默认 Python 是 3.9
# uv 会自动下载并使用正确版本
uv sync # 读取 .python-version 或 pyproject.toml 中的 requires-python
# 手动指定
uv venv --python 3.12
uv sync --python 3.12
# 检查当前使用的 Python
uv run python --version
poetry run python --version
# 删除并重建虚拟环境(解决版本错误问题)
rm -rf .venv
uv venv --python 3.12
uv sync
6. Poetry 虚拟环境位置混乱
# 默认情况下 Poetry 将虚拟环境放在系统缓存目录,不在项目内
# 建议修改为项目内,便于管理
poetry config virtualenvs.in-project true
# 此后虚拟环境创建在项目的 .venv 目录
# 查看当前配置
poetry config --list
# 查看已有虚拟环境
poetry env list
poetry env info
# 删除虚拟环境
poetry env remove python3.12
最佳实践
新项目优先选 uv:uv 安装速度比 pip 快 10–100 倍,内置 Python 版本管理(替代 pyenv),锁文件生成速度是 Poetry 的数十倍。Poetry 在需要发布 PyPI 包的复杂场景仍有优势。
提交 uv.lock 到版本控制:uv.lock 记录所有依赖的精确版本(含传递依赖),确保团队成员和 CI 环境使用完全相同的包版本,防止"我这里能跑"问题。
git add uv.lock
# 不要在 .gitignore 中排除 uv.lock
区分开发依赖和生产依赖:测试框架、类型检查工具、代码格式化工具不应进入生产镜像。用 dev group 隔离。
# uv
uv add --dev pytest mypy ruff
# Poetry
poetry add --group dev pytest mypy ruff
# 生产安装(不含 dev 依赖)
uv sync --no-dev
poetry install --only main
用 uv run 替代手动激活虚拟环境:uv run python script.py 自动在当前项目的虚拟环境中运行,无需每次 source .venv/bin/activate,也避免忘记激活导致的包找不到问题。
固定 Python 版本:在 pyproject.toml 中明确声明 requires-python,防止团队成员使用不兼容的 Python 版本。
[project]
requires-python = ">=3.12"
常见陷阱
陷阱:全局安装导致多项目依赖冲突
现象: 项目 A 需要 requests==2.28,项目 B 需要 requests==2.32,直接 pip install 后两个项目不能同时正常工作。
原因: 全局 Python 环境只能安装一个版本的包。
解决: 每个项目使用独立虚拟环境(uv 和 Poetry 均自动创建),互不干扰。
cd project_a && uv sync # 项目 A 独立环境
cd project_b && uv sync # 项目 B 独立环境
陷阱:直接编辑 pyproject.toml 添加依赖不更新锁文件
现象: 手动在 pyproject.toml 的 dependencies 列表中加了新包,但 CI 环境中安装后该包不在锁文件记录的版本范围内。
原因: 锁文件(uv.lock / poetry.lock)不会因为手动编辑 pyproject.toml 而自动更新,需要显式执行 uv lock / poetry lock 重新生成。
解决: 始终用命令添加依赖,让工具维护锁文件。
uv add requests # 自动更新 pyproject.toml 和 uv.lock
poetry add requests # 自动更新 pyproject.toml 和 poetry.lock
陷阱:虚拟环境路径问题导致 IDE 找不到包
现象: PyCharm / VS Code 的类型提示不工作,导入报红,但命令行运行没问题。
原因: IDE 配置的 Python 解释器路径不是项目虚拟环境中的 Python,而是全局 Python。
解决: IDE 中将解释器路径设为项目 .venv/bin/python(uv)或 poetry env info --path 输出的路径下的 Python。
# 查看 uv 项目的虚拟环境路径
uv python find
# 输出类似:.venv/bin/python
# Poetry
poetry env info --executable