春江暮客

春江暮客的个人学习分享网站

2026 Python 项目管理实战:用 uv 替代 pip、venv 和 pipx

2026-05-30 技术

很多 Python 项目一开始都很简单:创建虚拟环境、安装依赖、运行脚本。可项目一多,就容易遇到这些问题:

  1. venv 在哪里创建不统一
  2. pip install 后忘记更新 requirements.txt
  3. 本机 Python 版本和服务器不一致
  4. ruffpytesthttpie 这类 CLI 工具混在项目依赖里
  5. 新同事拉代码后不知道该执行哪几条命令

uv 的价值就在这里:它把 Python 版本、虚拟环境、依赖解析、锁文件、脚本运行和命令行工具管理放到一套命令里。本文不做概念堆叠,只给你一套可以直接复制的日常工作流。

完成后,你会掌握:

  1. 如何安装和验证 uv
  2. 如何创建一个带锁文件的 Python 项目
  3. 如何用 uv run 代替手动激活虚拟环境
  4. 如何运行单文件脚本
  5. 如何用 uvx 管理临时 CLI 工具
  6. 如何把老项目从 requirements.txt 迁移过来

什么场景适合优先用 uv

如果你正在维护下面这些项目,uv 很适合先引入:

  1. Python 脚本工具:爬虫、数据处理、日志分析、自动化运维
  2. Web 项目:FastAPI、Django、Flask
  3. AI 项目:LangChain、MCP Server、模型调用脚本
  4. CLI 工具:需要 ruffpytestmypyhttpie 等开发工具
  5. 多人协作项目:希望依赖版本可复现

如果只是服务器上一个永远不改的老脚本,也不一定要马上迁移。更务实的方式是:新项目直接用 uv,老项目在下一次改依赖时再迁移。

方法 1:安装 uv 并确认环境

1. macOS 和 Linux 安装

官方安装脚本最直接:

curl -LsSf https://astral.sh/uv/install.sh | sh

安装后重新打开终端,或者手动加载 shell 配置:

source ~/.zshrc

如果你用的是 Bash,通常是:

source ~/.bashrc

2. Windows 安装

在 PowerShell 里执行:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

3. 验证安装

uv --version
uv help

能看到版本号和子命令说明,就说明安装完成。

常用命令可以先记住这几个:

uv init
uv add
uv remove
uv sync
uv run
uv lock
uvx

方法 2:创建一个新 Python 项目

下面用一个小型天气 CLI 项目做示例。它会请求公开接口,然后打印城市天气摘要。

1. 初始化项目

uv init weather-cli
cd weather-cli

查看生成的文件:

ls -la

你会看到类似结构:

.
├── .git
├── .gitignore
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

.python-version 用来记录项目期望的 Python 版本,pyproject.toml 用来记录项目元数据和依赖。

2. 指定 Python 版本

如果你希望项目固定使用 Python 3.12,可以执行:

uv python install 3.12
uv python pin 3.12

再检查:

cat .python-version

预期输出:

3.12

3. 添加依赖

这个示例用 httpx 请求接口,用 rich 美化输出:

uv add httpx rich

执行后会更新两个关键文件:

  1. pyproject.toml:记录直接依赖
  2. uv.lock:锁定完整依赖树

提交代码时,建议把这两个文件都提交。

方法 3:用 uv run 运行项目

很多人第一次用 uv 时,最不习惯的是不再手动执行:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

uv 项目里,直接运行:

uv run python main.py

uv run 会检查环境是否存在、依赖是否同步,然后在项目环境里执行命令。

1. 编写示例代码

main.py 改成下面这样:

from __future__ import annotations

import sys

import httpx
from rich.console import Console
from rich.table import Table


console = Console()


def fetch_weather(city: str) -> dict:
    response = httpx.get(
        "https://geocoding-api.open-meteo.com/v1/search",
        params={"name": city, "count": 1, "language": "en", "format": "json"},
        timeout=10,
    )
    response.raise_for_status()
    data = response.json()
    results = data.get("results", [])
    if not results:
        raise ValueError(f"city not found: {city}")

    location = results[0]
    weather = httpx.get(
        "https://api.open-meteo.com/v1/forecast",
        params={
            "latitude": location["latitude"],
            "longitude": location["longitude"],
            "current": "temperature_2m,wind_speed_10m",
        },
        timeout=10,
    )
    weather.raise_for_status()
    current = weather.json()["current"]
    return {
        "name": location["name"],
        "country": location.get("country", ""),
        "temperature": current["temperature_2m"],
        "wind": current["wind_speed_10m"],
    }


def main() -> None:
    city = sys.argv[1] if len(sys.argv) > 1 else "Shanghai"
    result = fetch_weather(city)

    table = Table(title=f"Weather: {result['name']}, {result['country']}")
    table.add_column("Metric")
    table.add_column("Value")
    table.add_row("Temperature", f"{result['temperature']} C")
    table.add_row("Wind", f"{result['wind']} km/h")
    console.print(table)


if __name__ == "__main__":
    main()

运行:

uv run python main.py Shanghai

预期会看到一个表格,包含温度和风速。真实数值会随接口返回变化。

2. 不激活虚拟环境也能调试

你仍然可以看到 .venv

ls -la .venv

但日常开发不需要手动激活它。直接用:

uv run python main.py Beijing
uv run python -m pip list

这能减少“我到底在哪个虚拟环境里”的混乱。

方法 4:把开发工具放进 dev 依赖

项目运行依赖和开发工具应该分开。例如 httpx 是运行依赖,ruffpytest 更适合作为开发依赖。

添加开发依赖:

uv add --dev ruff pytest

运行格式和检查:

uv run ruff format .
uv run ruff check .

创建一个简单测试:

mkdir -p tests
cat > tests/test_smoke.py <<'EOF'
from main import fetch_weather


def test_fetch_weather_shanghai():
    result = fetch_weather("Shanghai")
    assert result["name"]
    assert "temperature" in result
EOF

运行测试:

uv run pytest

如果你不希望测试依赖真实网络,可以把 fetch_weather 拆成更小函数,并用 mock 替代 HTTP 请求。这里为了让示例短,保留真实请求版本。

方法 5:用 uvx 临时运行 CLI 工具

有些工具只是偶尔用一次,不应该写进项目依赖。例如你想临时格式化或检查一个目录:

uvx ruff check .

也可以临时运行第三方 CLI:

uvx httpie --version
uvx pycowsay "hello uv"

如果某个工具每天都用,可以安装成全局工具:

uv tool install ruff
ruff --version

简单判断规则:

  1. 项目必须复现的工具:用 uv add --dev
  2. 偶尔运行一次的工具:用 uvx
  3. 每天在多个项目都用的工具:用 uv tool install

方法 6:迁移已有 requirements.txt 项目

假设老项目结构是这样:

old-project
├── app.py
└── requirements.txt

requirements.txt 内容:

fastapi==0.115.0
uvicorn[standard]==0.30.6

1. 在原目录初始化

进入项目目录后执行:

uv init --bare

--bare 适合已有项目,它不会生成示例 main.py

2. 导入依赖

uv add -r requirements.txt

然后同步环境:

uv sync

3. 改造启动命令

以前可能是:

source .venv/bin/activate
uvicorn app:app --reload

迁移后可以改成:

uv run uvicorn app:app --reload

部署脚本里也建议用 uv sync --frozen,确保线上环境严格使用锁文件:

uv sync --frozen
uv run uvicorn app:app --host 0.0.0.0 --port 8000

验证:确认项目可复现

完成上面步骤后,用下面这组命令检查项目状态:

uv lock --check
uv sync --frozen
uv run python --version
uv run python main.py Shanghai

如果这些命令都能执行,说明项目的依赖声明、锁文件和运行入口基本可用。

建议提交这些文件:

git add pyproject.toml uv.lock .python-version main.py README.md
git commit -m "Use uv for Python project workflow"

团队协作时,新成员只需要:

git clone <repo-url>
cd weather-cli
uv sync
uv run python main.py Shanghai

常见问题和修复

1. 找不到 uv 命令

错误类似:

zsh: command not found: uv

先重新打开终端。如果仍然不行,检查安装目录是否在 PATH 里:

echo "$PATH"

macOS 和 Linux 上也可以重新执行安装脚本,然后按提示加载 shell 配置。

2. uv add 提示找不到 pyproject.toml

错误通常是因为你不在项目目录里。

修复:

cd weather-cli
uv add requests

如果这是一个已有项目,先执行:

uv init --bare

3. Python 版本不一致

先查看项目要求:

cat .python-version

安装并同步:

uv python install
uv sync

如果你想明确切到 3.12:

uv python install 3.12
uv python pin 3.12
uv sync

4. 锁文件和依赖声明不一致

如果 uv lock --check 失败,说明 pyproject.tomluv.lock 不匹配。

开发环境里更新锁文件:

uv lock

生产环境不要自动改锁文件,应该失败后回到开发机修复并重新提交。

5. 不知道该用 uv add 还是 uv pip install

日常项目开发优先用:

uv add package-name

这会更新 pyproject.tomluv.lock

uv pip install 更适合兼容传统 pip 工作流,例如临时维护旧环境。新项目建议尽量围绕 uv inituv adduv syncuv run 建立流程。

总结

uv 最实用的地方不是“命令更少”,而是把 Python 项目的关键流程统一起来:创建项目、锁定依赖、同步环境、运行命令、管理工具。对个人项目,它能减少虚拟环境和依赖文件的混乱;对团队项目,它能让新机器更快复现同一个运行环境。

建议新项目直接从 uv init 开始,老项目则先从 uv init --bareuv add -r requirements.txt 小步迁移。只要把 pyproject.tomluv.lock.python-version 提交好,后续运行基本就能收敛到一条命令:uv run

友情链接

其它