第 10 章 · 工程化基础¶
Java 工程师习惯了 Maven/Gradle 的"一站式"体验:一个 pom.xml 声明依赖、构建工具管 classpath、IDE 集成一切。Python 的工程化历史上很碎片化,但已收敛到 pyproject.toml + 虚拟环境的现代标准。本章两条路并行:路线一(主推)uv——最接近 Maven/Gradle 的现代统一工具;路线二 pip + venv——最通用、企业环境最常见。
10.1 为什么要虚拟环境¶
Java 每个 Maven 项目靠依赖坐标 + 本地仓库 ~/.m2 隔离,全局一个 JDK。Python 不同:第三方包装进解释器的 site-packages,默认全局共享。如果所有项目共用一个全局环境,A 项目要 django==3、B 项目要 django==5 就冲突了。
虚拟环境(virtual environment) = 一个项目专属的、独立的 Python 环境(独立 site-packages)。每个项目一个,互不干扰。
-
Java 心智
-
Python 心智
10.2 路线一:uv(主推,现代统一工具)¶
uv 是 Rust 写的、极快的现代工具链,把 venv + pip + pip-tools + 甚至 poetry 的依赖管理统一到一个命令——最接近你熟悉的 Maven/Gradle。
# 安装(若尚未安装)
pip install uv # 或用官方安装脚本
# 新项目
uv init myproject # 生成 pyproject.toml 等
cd myproject
# 管理依赖
uv add requests # 加依赖(自动写进 pyproject.toml、装进 .venv、更新 uv.lock)
uv add --dev pytest # 开发依赖
uv remove requests # 移除
# 同步环境(按 pyproject.toml + uv.lock 复现环境)
uv sync # 别人 clone 后第一条命令
# 运行
uv run python main.py # 在项目环境里运行
uv run pytest # 在项目环境里跑测试
uv.lock 相当于 Maven 的锁定版本——保证团队/CI 装出完全一致的依赖版本。
为什么主推 uv
一个工具搞定"环境创建 + 依赖声明 + 版本锁定 + 运行",速度快(比 pip 快 10-100 倍),心智模型最接近 Maven/Gradle。2026 年已是社区主流推荐。
10.3 路线二:pip + venv(传统,最通用)¶
没有 uv 的环境(企业受限网络、CI 基础镜像)用标准库自带的 venv + pip:
# 1. 创建虚拟环境
python -m venv .venv
# 2. 激活(Windows PowerShell / bash)
.venv\Scripts\activate # Windows CMD
.venv/Scripts/activate # Windows Git Bash / source 形式
source .venv/bin/activate # macOS/Linux
# 3. 装依赖
pip install requests pytest
pip install -r requirements.txt
# 4. 冻结当前版本(生成 requirements.txt)
pip freeze > requirements.txt
requirements.txt 是传统的依赖清单(每行一个 包==版本)。激活后命令行提示符会出现 (.venv) 前缀,表示当前在虚拟环境里。
⚠️ Java 程序员的陷阱
- 别用
pip install装到全局解释器——养成"先建/激活 .venv 再装"的习惯。 requirements.txt是扁平列表,不像pom.xml那样有依赖树/坐标体系;要可复现的锁定,pip 生态有pip-tools生成requirements.lock。这也是 uv 的优势之一。
10.4 pyproject.toml:Python 的 pom.xml¶
pyproject.toml(PEP 621)是现代 Python 项目的唯一标准配置文件,取代老的 setup.py:
[project]
name = "myapp"
version = "0.1.0"
description = "My app"
requires-python = ">=3.13"
dependencies = [
"requests>=2.32",
"pydantic>=2",
]
[project.optional-dependencies]
dev = ["pytest>=8", "mypy>=1.10", "ruff>=0.5"]
[project.scripts]
myapp = "myapp.cli:main" # 安装后提供 `myapp` 命令(贯穿项目会用)
# 各工具的配置也放这里:
[tool.mypy]
python_version = "3.13"
strict = true
[tool.pytest.ini_options]
testpaths = ["tests"]
[tool.ruff]
line-length = 100
对照:
| Java | Python | |
|---|---|---|
| 项目元数据 + 依赖 | pom.xml / build.gradle |
pyproject.toml |
| 锁定版本 | Gradle lock / Maven enforcer | uv.lock |
| 可执行入口 | main-class / application 插件 |
[project.scripts] |
10.5 项目结构:src 布局¶
推荐 src layout(避免测试意外导入到本地源码、更接近安装后的结构):
myapp/
├── pyproject.toml
├── uv.lock
├── src/
│ └── myapp/
│ ├── __init__.py
│ ├── cli.py
│ └── core.py
└── tests/
├── __init__.py
└── test_core.py
10.6 测试:pytest(vs JUnit)¶
pytest 是 Python 事实标准的测试框架,比 unittest(标准库,类 JUnit 风格)更简洁:
-
Java JUnit
-
Python pytest
三个关键差异:
- 用裸
assert,不用assertEquals/assertThat——失败时 pytest 自动给出详细对比。 - 测试是普通函数,不用类(也可用类组织)。
- 文件名
test_*.py、函数名test_*即被自动发现。
fixture(vs @Before)¶
import pytest
@pytest.fixture
def sample_user():
return User("Alice")
def test_greet(sample_user): # 参数名匹配 fixture,自动注入
assert sample_user.name == "Alice"
参数化(vs @ParameterizedTest)¶
@pytest.mark.parametrize("a, b, expected", [
(1, 2, 3),
(10, 5, 15),
(-1, 1, 0),
])
def test_add(a, b, expected):
assert add(a, b) == expected
运行:
Pythonic 写法
- 测试函数依赖注入靠 fixture(
conftest.py里放共享 fixture),比 JUnit 的@Before灵活。 - 断言失败信息由 pytest 自动美化,不需要手写消息。
10.7 调试与格式化¶
调试:breakpoint()¶
进入后可用 n(下一步)、s(步入)、p var(打印)、c(继续)、l(看代码)。比 Java 的 System.out.println 调试强大,但 IDE(PyCharm/VSCode)的图形调试器更友好。
Lint + 格式化:ruff¶
ruff(Rust 写,极快)一个工具取代 flake8 + black + isort,相当于 Java 的 Checkstyle + Spotless:
本章练习¶
练习 10.1
说明"在全局 Python 里 pip install 业务依赖"为什么不推荐,以及虚拟环境如何解决。
参考答案
全局 site-packages 被所有项目共享,会导致:不同项目依赖同一库的不同版本时冲突、升级一个库破坏另一个项目、难以复现环境。虚拟环境给每个项目一份独立的 site-packages,依赖彼此隔离,且可通过 requirements.txt/uv.lock 精确复现。
练习 10.2
用 uv 从零建一个项目 calc:加 pytest 为开发依赖,写一个 add 函数和它的测试,运行测试通过。
参考答案
uv run 会以可编辑模式装好本项目。)
练习 10.3
把下面 JUnit 风格测试改写成 pytest 风格(裸 assert + 参数化):
@ParameterizedTest
@CsvSource({"1,2,3", "10,5,15"})
void addWorks(int a, int b, int expected) {
assertEquals(expected, add(a, b));
}
参考答案
上一章:第 9 章 · 标准库对照速查 | 下一章:第 11 章 · 并发模型。