第3章:目录结构设计
说到项目目录结构,我见过太多新手上来就写代码,写到一半发现配置文件没地方放,测试代码和业务代码混在一起,最后整个项目乱成一锅粥。嗯,今天我们就来聊聊怎么把这件事做对。
3.1 标准Python项目目录结构
先给你看一个我用了多年的标准结构。说实话,这个结构不是我发明的,而是从多个开源项目里提炼出来的。你想想看,能同时被Django、Flask、Requests这些知名项目采用的结构,肯定有它的道理。
my_project/
├── src/
│ └── my_project/
│ ├── __init__.py
│ ├── main.py
│ ├── config.py
│ ├── models/
│ ├── services/
│ └── utils/
├── tests/
│ ├── __init__.py
│ ├── test_main.py
│ └── test_services/
├── scripts/
│ ├── setup.sh
│ └── deploy.sh
├── docs/
├── requirements/
│ ├── base.txt
│ ├── dev.txt
│ └── prod.txt
├── .env.example
├── .gitignore
├── Makefile
├── pyproject.toml
└── README.md
为什么要有两层 src/my_project?我刚开始也觉得多此一举。直到有一次,我在一个大型微服务项目里,发现多个包名冲突,改得我头皮发麻。后来才明白,这层 src 目录其实是个命名空间保护伞。
核心原则:src 目录只放源码,tests 目录只放测试,两者互不干扰。这是项目健康度的基本保障。
3.2 src与tests分离
为什么要分离?说白了就三个字:解耦合。测试代码和业务代码混在一起,就像把厨房和厕所建在一个房间里——虽然能用,但总觉得不对劲。
我曾经接手过一个项目,测试文件散落在各个业务模块里。想跑个单元测试,得先搞清楚哪些是测试文件,哪些是业务文件。更可怕的是,有人把测试代码直接 import 到了生产环境里……嗯,那场面,你懂的。
3.2.1 测试目录的最佳实践
| 目录 | 用途 | 注意事项 |
|---|---|---|
| tests/unit | 单元测试 | 测试单个函数或类 |
| tests/integration | 集成测试 | 测试模块间交互 |
| tests/e2e | 端到端测试 | 模拟真实用户场景 |
| tests/fixtures | 测试数据 | 存放 mock 数据和配置文件 |
我的小技巧:测试文件的命名尽量和源码保持一致。比如 src/my_project/services/user_service.py 对应 tests/unit/services/test_user_service.py。这样找测试文件时,闭着眼睛都能摸到。
3.3 配置文件与脚本的放置
配置文件放哪里?这个问题看似简单,但坑不少。我见过有人把数据库密码直接写在代码里,也见过把配置文件塞进版本控制系统的。嗯,这些都是血泪教训。
3.3.1 配置文件的分类
我个人习惯把配置文件分成三类:
- 环境配置:数据库连接、、环境变量等。这些用
.env文件管理,不提交到 Git。 - 应用配置:日志级别、缓存策略、超时时间等。放在
config/目录下,用 YAML 或 TOML 格式。 - 构建配置:依赖管理、打包参数等。用
pyproject.toml或setup.cfg。
# .env 示例(不要提交到 Git)
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
SECRET_KEY=your-secret-key-here
DEBUG=True
# config/app.yaml 示例(可以提交到 Git)
server:
host: "0.0.0.0"
port: 8000
workers: 4
logging:
level: "INFO"
format: "json"
注意:千万不要把 .env 文件提交到 Git 仓库!我曾经见过一个团队,因为不小心把生产环境的 .env 提交了,导致数据库密码泄露。正确的做法是提交 .env.example,里面只放占位符。
3.3.2 脚本文件的组织
脚本文件我习惯放在 scripts/ 目录下。为什么不用 bin/ 或 tools/?其实都可以,但 scripts/ 更直观,一看就知道是辅助脚本。
常见的脚本类型:
- setup.sh:项目初始化脚本,安装依赖、创建虚拟环境
- deploy.sh:部署脚本,构建镜像、推送服务器
- migrate.sh:数据库迁移脚本
- clean.sh:清理临时文件、缓存
# scripts/setup.sh
#!/bin/bash
# 项目初始化脚本
echo "Creating virtual environment..."
python3 -m venv venv
echo "Activating virtual environment..."
source venv/bin/activate
echo "Installing dependencies..."
pip install -r requirements/dev.txt
echo "Setting up pre-commit hooks..."
pre-commit install
echo "Done! Run 'source venv/bin/activate' to start."
3.4 目录结构的演进
你可能会问:这个结构是不是一成不变的?当然不是。项目从小到大会经历几个阶段:
| 阶段 | 目录结构 | 特点 |
|---|---|---|
| 原型阶段 | 单个 Python 文件 | 快速验证想法 |
| 小型项目 | src + tests 分离 | 开始关注可维护性 |
| 中型项目 | 增加 scripts、docs、config | 团队协作需求出现 |
| 大型项目 | 多模块、微服务 | 需要独立部署和版本管理 |
我个人建议,从第一天就用标准结构。别想着「等项目大了再重构」——重构的成本往往比你想象的高得多。
3.5 避坑指南
最后,分享几个我踩过的坑:
- 不要用
src/作为包名:from src import xxx这种写法很丑,而且容易和系统路径冲突。 - 测试目录不要加
__init__.py:除非你用了pytest的某些特殊功能,否则不需要。 - 配置文件不要硬编码路径:用环境变量或命令行参数传递,这样部署时更灵活。
- 脚本文件要加执行权限:
chmod +x scripts/*.sh,不然别人用的时候会一脸懵。
总结一下:好的目录结构就像好的房间布局——你不需要每天想着它,但它能让你的生活顺畅很多。花 10 分钟设计好结构,能省下未来 100 小时的调试时间。这笔账,怎么算都划算。