Python 包管理最佳实践——Poetry、uv、虚拟环境、私有仓库完整方案
2026/4/30大约 6 分钟
Python 包管理最佳实践——Poetry、uv、虚拟环境、私有仓库完整方案
适读人群:在 Python 依赖管理上踩过坑、想建立规范包管理体系的工程师 | 阅读时长:约 15 分钟 | 核心价值:建立从开发到生产的完整 Python 包管理规范,告别依赖冲突
"在我电脑上是好的"的根源
组里有个新来的同学,把项目跑起来用了整整半天。根本原因是:他全局安装了各种 Python 包,版本和项目要求的对不上,每次 pip install 都会覆盖旧版本,搞得一团糟。
这种混乱在 Java 项目里很少发生——Maven/Gradle 会把所有依赖锁定到精确版本,本地缓存和项目隔离做得很好。
Python 也能做到一样规范,但需要你主动去配置。
这篇文章,从最基础的虚拟环境讲起,到 Poetry 的完整工作流,再到 uv 这个新锐工具,帮你建立一套生产级的 Python 包管理体系。
一、虚拟环境:Python 依赖隔离的基础
1.1 为什么必须用虚拟环境
# 没有虚拟环境的噩梦
项目A 需要 requests==2.28.0
项目B 需要 requests==2.31.0
全局安装 → 两个版本只能共存一个 → 总有一个项目跑不起来1.2 venv:内置虚拟环境
# 创建虚拟环境
python -m venv .venv
# 激活(macOS/Linux)
source .venv/bin/activate
# 激活(Windows PowerShell)
.venv\Scripts\Activate.ps1
# 验证
which python # 应该指向 .venv/bin/python
python --version
# 安装依赖
pip install fastapi uvicorn sqlalchemy
# 导出依赖
pip freeze > requirements.txt
# 根据 requirements.txt 安装
pip install -r requirements.txt
# 退出虚拟环境
deactivate目录结构惯例:
project/
├── .venv/ # 虚拟环境(加入 .gitignore)
├── .gitignore
├── requirements.txt
└── src/
└── main.py二、Poetry:完整的项目管理工具
Poetry 是目前最成熟的 Python 项目管理工具,相当于 Python 版的 Maven + npm 的合体。
2.1 安装 Poetry
# 官方推荐安装方式(不要用 pip install poetry!)
curl -sSL https://install.python-poetry.org | python3 -
# 验证
poetry --version2.2 项目初始化
# 新项目
poetry new my-project
# 已有项目
cd existing-project
poetry init
# 生成的 pyproject.toml# pyproject.toml
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "老张的 AI 工具项目"
authors = ["老张 <laoz@example.com>"]
readme = "README.md"
python = ">=3.11"
[tool.poetry.dependencies]
python = ">=3.11"
fastapi = "^0.111.0"
uvicorn = {extras = ["standard"], version = "^0.29.0"}
sqlalchemy = {extras = ["asyncio"], version = "^2.0"}
pydantic = "^2.7"
httpx = "^0.27.0"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0"
pytest-asyncio = "^0.23"
mypy = "^1.10"
ruff = "^0.4"
black = "^24.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry-core.masonry.api"2.3 常用命令
# 安装依赖(自动创建虚拟环境,生成 poetry.lock)
poetry install
# 添加依赖
poetry add pydantic
poetry add pytest --group dev
# 更新依赖
poetry update
poetry update pydantic # 只更新指定包
# 移除依赖
poetry remove requests
# 查看依赖树
poetry show --tree
# 运行脚本(自动激活虚拟环境)
poetry run python main.py
poetry run pytest
# 导出 requirements.txt(CI/CD 用)
poetry export -f requirements.txt --output requirements.txt --without-hashes
# 发布到 PyPI
poetry publish --build2.4 版本约束语法
# ^ : 兼容更新(只允许非 breaking 版本)
fastapi = "^0.111.0" # >=0.111.0, <0.112.0(次版本号可以升)
# ~ : 补丁更新(只允许 patch 版本)
pydantic = "~2.7.0" # >=2.7.0, <2.8.0
# 精确版本
redis = "4.6.0"
# 范围
python = ">=3.10,<4.0"三、uv:下一代 Python 包管理器
uv 是 Astral 公司用 Rust 编写的超快 Python 包管理工具,pip 的直接替代,速度比 pip 快 10-100 倍。
3.1 安装 uv
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
# 验证
uv --version3.2 uv 基础用法
# 替代 pip
uv pip install fastapi # 比 pip 快 10x
uv pip install -r requirements.txt
uv pip freeze
# 替代 venv
uv venv .venv
uv venv --python 3.12 .venv # 指定 Python 版本
# 替代 pip-compile(锁定精确版本)
uv pip compile requirements.in -o requirements.txt
# 项目管理(类 Poetry)
uv init my-project
uv add fastapi
uv add pytest --dev
uv run python main.py
uv sync # 安装 pyproject.toml 中的所有依赖3.3 uv vs Poetry 怎么选
| 维度 | Poetry | uv |
|---|---|---|
| 安装速度 | 快 | 极快(Rust,10-100x) |
| 成熟度 | 高(5年+) | 较新(2024 年发布) |
| 锁文件 | poetry.lock | uv.lock |
| 虚拟环境 | 自动管理 | 需要手动 or 自动 |
| 发布到 PyPI | 内置 | 需要 twine |
| 生态兼容 | 好 | 兼容 PEP 517/518 |
| 推荐场景 | 完整项目管理 | 纯依赖安装加速 |
老张建议:新项目用 uv,旧项目用 Poetry 继续。uv 可以和 Poetry 配合(用 uv 加速 pip 操作)。
四、私有仓库配置
4.1 PyPI 私有仓库(Nexus/JFrog)
# pip 配置私有仓库
pip config set global.index-url https://pypi.your-company.com/simple/
pip config set global.trusted-host pypi.your-company.com
# 或在 pip.ini / pip.conf
[global]
index-url = https://pypi.your-company.com/simple/
extra-index-url = https://pypi.org/simple/
trusted-host = pypi.your-company.com# Poetry 配置私有仓库
# pyproject.toml
[[tool.poetry.source]]
name = "company-nexus"
url = "https://nexus.company.com/repository/pypi-proxy/simple/"
priority = "primary"
[[tool.poetry.source]]
name = "pypi"
priority = "supplemental"# Poetry 添加认证
poetry config http-basic.company-nexus username password4.2 uv 配置私有仓库
# pyproject.toml
[tool.uv.pip]
index-url = "https://pypi.your-company.com/simple/"
extra-index-url = ["https://pypi.org/simple/"]# 环境变量认证
UV_INDEX_URL=https://pypi.your-company.com/simple/
UV_HTTP_BASIC_COMPANY_USERNAME=user
UV_HTTP_BASIC_COMPANY_PASSWORD=pass五、完整可运行示例:项目初始化脚本
#!/usr/bin/env python3
"""
Python 项目初始化脚本
自动生成标准目录结构、pyproject.toml、.gitignore 等
"""
import os
import subprocess
import sys
from pathlib import Path
def create_project_structure(project_name: str, use_uv: bool = True) -> None:
"""创建标准 Python 项目结构"""
project_dir = Path(project_name)
project_dir.mkdir(exist_ok=True)
# 创建目录结构
dirs = [
"src",
f"src/{project_name.replace('-', '_')}",
"tests",
"scripts",
]
for d in dirs:
(project_dir / d).mkdir(parents=True, exist_ok=True)
# 生成 pyproject.toml
pkg_name = project_name.replace("-", "_")
pyproject = f"""[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "{project_name}"
version = "0.1.0"
description = "TODO: 项目描述"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"fastapi>=0.111.0",
"uvicorn[standard]>=0.29.0",
"pydantic>=2.7",
"httpx>=0.27.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=5.0",
"ruff>=0.4",
"mypy>=1.10",
]
[tool.ruff]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "UP", "B", "I"]
ignore = ["E501"]
[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
[tool.coverage.run]
source = ["src"]
omit = ["*/tests/*"]
"""
(project_dir / "pyproject.toml").write_text(pyproject)
# 生成 .gitignore
gitignore = """.venv/
.uv/
__pycache__/
*.pyc
*.pyo
.pytest_cache/
.mypy_cache/
.ruff_cache/
htmlcov/
.coverage
dist/
build/
*.egg-info/
.env
.env.local
"""
(project_dir / ".gitignore").write_text(gitignore)
# 生成主模块 __init__.py
init_content = f'"""{ project_name } - TODO: 包描述"""\n\n__version__ = "0.1.0"\n'
(project_dir / "src" / pkg_name / "__init__.py").write_text(init_content)
# 生成 Makefile
makefile = f"""# {project_name} Makefile
.PHONY: install dev test lint fmt typecheck clean
install:
\tuv sync
dev:
\tuv sync --extra dev
test:
\tuv run pytest tests/ -v --cov=src --cov-report=term-missing
lint:
\tuv run ruff check src/ tests/
fmt:
\tuv run ruff format src/ tests/
typecheck:
\tuv run mypy src/
clean:
\trm -rf .venv dist build *.egg-info .coverage htmlcov
"""
(project_dir / "Makefile").write_text(makefile)
print(f"项目 '{project_name}' 创建完成!")
print(f"\n目录结构:")
for path in sorted(project_dir.rglob("*")):
if ".venv" not in str(path):
indent = " " * (len(path.relative_to(project_dir).parts) - 1)
print(f" {indent}{path.name}")
print(f"\n下一步:")
if use_uv:
print(f" cd {project_name}")
print(f" uv sync --extra dev")
print(f" uv run pytest")
else:
print(f" cd {project_name}")
print(f" poetry install")
print(f" poetry run pytest")
def main():
if len(sys.argv) < 2:
print("用法: python create_project.py <project-name> [--poetry]")
print("示例: python create_project.py my-ai-project")
sys.exit(1)
project_name = sys.argv[1]
use_poetry = "--poetry" in sys.argv
if not project_name.replace("-", "").replace("_", "").isalnum():
print(f"项目名称只能包含字母、数字、连字符和下划线")
sys.exit(1)
create_project_structure(project_name, use_uv=not use_poetry)
if __name__ == "__main__":
main()六、踩坑实录 1:requirements.txt 没有锁定版本
# 错误:不写版本号,今天装和明天装的版本可能不同
# requirements.txt
fastapi
uvicorn
sqlalchemy
# 正确:锁定版本(开发环境用 pip freeze 生成,CI/CD 用这个文件)
fastapi==0.111.0
uvicorn==0.29.0
sqlalchemy==2.0.30
# 更好:用 requirements.in(宽泛约束)+ requirements.txt(锁定版本)
# requirements.in
fastapi>=0.111.0
uvicorn>=0.29.0
# 生成锁定文件
uv pip compile requirements.in -o requirements.txt七、踩坑实录 2:Poetry 虚拟环境放在全局目录
# 默认 Poetry 把虚拟环境放在 ~/.cache/pypoetry/virtualenvs/
# 不直观,不好找
# 推荐:让 Poetry 在项目目录内创建 .venv
poetry config virtualenvs.in-project true
# 之后所有新项目都会在项目目录里创建 .venv/八、踩坑实录 3:Python 版本不一致
# 问题:本地 Python 3.12,CI 上 Python 3.10,行为不一致
# 解法:用 .python-version 文件固定 Python 版本(pyenv/uv 会读取)
echo "3.12.3" > .python-version
# 或在 pyproject.toml 中声明
[project]
requires-python = ">=3.11,<3.13"
# CI 中也强制使用相同版本
# .github/workflows/ci.yml
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version总结
Python 包管理的最佳实践:
- 永远使用虚拟环境:venv、Poetry、uv 都行,别全局装包
- 锁定依赖版本:poetry.lock 或 uv.lock 提交到 git
- 区分开发和生产依赖:
[dev]或--group dev - 新项目推荐 uv:速度快,兼容 PEP 标准
- CI/CD 用 requirements.txt:从 poetry.lock 或 uv.lock 导出
