别再乱放文件了,Python项目结构这么搭最省心
项目中建新文件的时候我经常想一个问题这个文件放哪工具类放 utils还是 helpers还是 common还是 lib每个项目都有自己的叫法。换了项目又要重新猜。去年重构了一个老项目把这个问题彻底想了一遍。记录一下结论。先说项目长什么样一个 Python 项目最怕的就是平铺——所有文件堆在一个目录里几百个 .py 谁也找不到谁。我现在的标准布局是这样project/├── src/│ └── project/│ ├── __init__.py│ ├── main.py│ ├── config.py│ ├── models/│ ├── services/│ ├── repositories/│ └── utils/├── tests/│ ├── conftest.py│ └── test_services/├── scripts/├── docs/└── pyproject.toml说几个关键点。src 目录以前我喜欢把代码直接放根目录后来发现几个问题第一导入的时候容易搞混。项目里的 test.py 和 Python 标准库的 test 重名了跑的时候导入的是自己那个同事 review 的时候看半天才发现。第二打包的时候 src 目录能把项目代码和配置文件分开。setup.py、pyproject.toml、README 这些在根目录代码在 src 里不会混在一起。第三测试好写。用 src 布局安装项目的时候 pip install -e . 就能在测试里 import project而不是靠 PYTHONPATH 硬凑。config 单独放一个文件config.py 里放什么我的规矩是只放配置读取逻辑不放业务代码。python# config.pyimport osfrom dataclasses import dataclass, fielddataclassclass DatabaseConfig:host: str localhostport: int 5432name: str appdataclassclass RedisConfig:host: str localhostport: int 6379dataclassclass AppConfig:env: str developmentdebug: bool Truedb: DatabaseConfig field(default_factoryDatabaseConfig)redis: RedisConfig field(default_factoryRedisConfig)def load_config() - AppConfig:cfg AppConfig()cfg.env os.getenv(APP_ENV, development)cfg.debug cfg.env developmentcfg.db.host os.getenv(DB_HOST, localhost)cfg.db.port int(os.getenv(DB_PORT, 5432))return cfg不把 os.getenv 散落在各个文件里所有配置来源集中在一个文件改配置字段的时候只改一个地方。models、services、repositories 三兄弟这是我从 DDD 那里抄来的简化版。不搞那么复杂核心就三个概念models 存数据结构不存逻辑。dataclass 或者 Pydantic只定义字段和校验。python# models/user.pyfrom dataclasses import dataclass, fieldfrom datetime import datetimedataclassclass User:id: intname: stremail: strcreated_at: datetime field(default_factorydatetime.now)repositories 存数据操作不存业务。怎么从数据库拿数据、怎么存进去放在这里。python# repositories/user_repo.pyfrom models.user import Userclass UserRepository:def __init__(self, db_session):self._session db_sessiondef get_by_id(self, user_id: int) - User | None:row self._session.execute(SELECT * FROM users WHERE id ?, (user_id,)).fetchone()if row:return User(**row)return Nonedef save(self, user: User) - None:self._session.execute(INSERT INTO users (id, name, email, created_at) VALUES (?, ?, ?, ?),(user.id, user.name, user.email, user.created_at),)self._session.commit()services 存业务逻辑不关心数据来源。比如用户注册、发邮件、算积分。python# services/user_service.pyfrom models.user import Userfrom repositories.user_repo import UserRepositoryclass UserService:def __init__(self, repo: UserRepository):self._repo repodef register(self, name: str, email: str) - User:user User(idNone, namename, emailemail)existing self._repo.get_by_email(email)if existing:raise ValueError(f邮箱 {email} 已被注册)self._repo.save(user)return user这样分的好处是改数据库从 MySQL 换到 PostgreSQL只改 repositoriesservices 完全不用动。改注册逻辑只改 services管你数据放哪。tests 怎么组织测试目录结构和 src 对应方便找。tests/├── conftest.py├── test_services/│ └── test_user_service.py└── test_repositories/└── test_user_repo.py每个测试文件对应一个源文件test_user_service.py 测 services/user_service.py不混在一起。conftest.py 里放公共 fixture别每个文件都写一遍。python# tests/conftest.pyimport pytestfrom repositories.user_repo import UserRepositoryfrom services.user_service import UserServicepytest.fixturedef user_repo():return UserRepository(db_session:memory:)pytest.fixturedef user_service(user_repo):return UserService(repouser_repo)踩过的几个坑1. utils 目录不应该存在。或者只应该放纯函数——日期格式化、字符串处理这种。把业务逻辑塞进 utils 是个坏习惯因为它会变成垃圾场什么东西都能往里扔。我见过一个项目 utils.py 一万行。2. services 和 repositories 不要互相引用。service 依赖 reporepo 不要依赖 service。否则改一个地方可能影响一串。3. 测试不要依赖实体的 __init__ 方法里自动生成的东西。比如 created_at 用 datetime.now()测的时候时间不一致断言失败。改成显式传参测试里自己控制。4. 别过早拆分。项目只有三个文件的时候不用搞 models/services/repositories。等 services 目录里有了三个文件再拆。先让代码跑起来再让它变整齐。5. 大项目可以考虑加一个 interfaces 目录放抽象类这样 services 依赖抽象而不是具体实现。小项目不用直接依赖就行以后需要再提取接口。用了半年这个结构之前一个项目几个月没碰回来打开代码目录扫一眼就知道去哪改——用户相关去 services/user_service.py数据操作去 repositories/user_repo.py配置去 config.py。不用回忆不用翻整个目录。新同事上手也快。之前带人先花半小时讲项目结构。现在说一句models 存数据services 存逻辑repos 存数据库操作基本懂了。项目结构说白了就是个放文件的地方但放对了后面省很多事。

相关新闻

Bloome多AI智能体协作平台:从原理到实战的完整指南

Bloome多AI智能体协作平台:从原理到实战的完整指南

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 在AI技术快速发展的今天,每个领域都涌现出专业的AI专家,但真正的挑战在于如何让这些专家协同工作。Bloome作为…

2026/7/10 12:22:11阅读更多 →
GKD_THS_List终极指南:三步决策法选择最适合你的自动化订阅源

GKD_THS_List终极指南:三步决策法选择最适合你的自动化订阅源

GKD_THS_List终极指南:三步决策法选择最适合你的自动化订阅源 【免费下载链接】GKD_THS_List GKD第三方订阅收录名单 项目地址: https://gitcode.com/gh_mirrors/gk/GKD_THS_List GKD_THS_List是GKD自动化工具的核心订阅源集合平台,汇集了7大主流…

2026/7/10 12:22:11阅读更多 →
从零构建AI大模型应用:基于RAG与LoRA的金融问答机器人实战指南

从零构建AI大模型应用:基于RAG与LoRA的金融问答机器人实战指南

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 想学AI大模型,但被“Transformer架构”、“LoRA微调”、“RAG检索”这些术语劝退?看到GitHub上动辄80K星标的项…

2026/7/10 12:22:11阅读更多 →
ChatGPT API并发瓶颈突破指南:从50→5000 RPS的4步熔断+异步批处理架构落地实录

ChatGPT API并发瓶颈突破指南:从50→5000 RPS的4步熔断+异步批处理架构落地实录

更多请点击: https://codechina.net 第一章:ChatGPT API并发调用优化的演进背景与挑战全景 随着大语言模型应用从单点实验快速走向生产级服务,ChatGPT API 的调用模式正经历从串行试探到高并发调度的根本性转变。早期开发者常以简单循环逐条…

2026/7/10 13:17:18阅读更多 →
AQS源码解读

AQS源码解读

retrantlock:A、B、C3个线程,假设A线程lock()时候拿到了锁,state被A设置成了1。static final class NonfairSync extends Sync {private static final long serialVersionUID 7316153563782823691L;/*** Performs lock. Try immediate barg…

2026/7/10 13:17:18阅读更多 →
LangChain Memory 架构演进全图谱(2022–2024核心迭代路径与企业级选型决策树)

LangChain Memory 架构演进全图谱(2022–2024核心迭代路径与企业级选型决策树)

更多请点击: https://intelliparadigm.com 第一章:LangChain Memory 的本质与演进动因 LangChain Memory 并非传统意义上的数据缓存,而是一种面向对话状态管理的抽象层,其核心职责是在链式调用(Chain)中持…

2026/7/10 13:17:18阅读更多 →
Java 8种基本数据类型实战:从内存占用到精度丢失的3个关键场景分析

Java 8种基本数据类型实战:从内存占用到精度丢失的3个关键场景分析

Java 8种基本数据类型实战:从内存占用到精度丢失的3个关键场景分析1. 基本数据类型概述与内存占用对比Java作为一门强类型语言,其8种基本数据类型构成了程序中最基础的数据存储单元。理解它们的特性和适用场景,是写出高效、健壮代码的前提。让…

2026/7/10 13:17:18阅读更多 →
Python 库 functools 详解

Python 库 functools 详解

functools模块是Python的标准库的一部分,它是为高阶函数而实现的。高阶函数是作用于或返回另一个函数或多个函数的函数。一般来说,对这个模块而言,任何可调用的对象都可以作为一个函数来处理。 functools 提供了 11 个函数: 1. …

2026/7/10 13:17:18阅读更多 →
Claude Code 回复完成?让鼠标告诉你

Claude Code 回复完成?让鼠标告诉你

不只是提示音——用 RGB 鼠标做 Claude Code 的状态指示灯用 Claude Code 写代码时,经常切到其他窗口等回复。切回来早了打断推理,切晚了浪费时间。它自带的提示音一闪而过,很容易错过。我直接把桌面上那只吃灰的罗技 G102 改成了**物理状态灯…

2026/7/10 13:12:18阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/10 12:10:00阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/10 12:29:21阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/10 4:59:05阅读更多 →
浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比

浏览器缓存行为深度解析:Chrome/Firefox/Safari 对 304 响应的 5 种触发场景对比当你在浏览器地址栏敲入一个网址时,背后可能隐藏着一场关于"要不要重新下载资源"的精密博弈。这场博弈的裁判是HTTP缓存机制,而304状态码则是这场博弈…

2026/7/10 0:00:01阅读更多 →
RoboWits:面向创造性问题求解的双臂机器人认知推理基准

RoboWits:面向创造性问题求解的双臂机器人认知推理基准

1. 项目概述:这不是又一个机器人抓取数据集,而是一次对“思考力”的压力测试 RoboWits——这个名字里藏着两个关键信号:“Robo”直指物理世界中的具身智能体,“Wits”则毫不掩饰地指向人类最核心的认知能力:机敏、判断…

2026/7/10 0:00:01阅读更多 →
5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能

5分钟完全指南:如何使用TegraRcmGUI图形化工具解锁Switch无限可能 【免费下载链接】TegraRcmGUI C GUI for TegraRcmSmash (Fuse Gele exploit for Nintendo Switch) 项目地址: https://gitcode.com/gh_mirrors/te/TegraRcmGUI TegraRcmGUI是一款专为Windows…

2026/7/10 0:00:01阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/9 9:45:20阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/9 15:50:44阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/9 14:14:17阅读更多 →