Python 项目结构与模块架构设计指南:从目录布局到公开 API 的完整实践
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
本指南基于 agents 仓库中python-project-structure技能文档展开,系统讲解 Python 项目的模块边界划分、目录结构组织、__all__公开接口设计与测试文件摆放策略,并结合仓库内plugin-eval子项目的真实源码佐证各模式的实际落地方式。读完本文,你将掌握一套可直接套用的 Python 项目组织方法论,能够独立规划新项目骨架、重构混乱代码库,并设计出可发现、可预测、易维护的模块结构。
使用场景:何时需要项目结构设计
结构化组织并不是新项目的专利,以下场景都应主动引入这套方法论:
- 从零启动一个新的 Python 项目;
- 为提升可读性而重构既有代码库;
- 通过
__all__定义模块的公开 API; - 在扁平结构与嵌套目录之间做出取舍;
- 确定测试文件的摆放策略;
- 创建可供他人复用的库包。
仓库中的plugin-eval子项目就是一套完整的实践样本:它采用src/布局组织源码,用tests/平行目录承载全部测试,并用pyproject.toml统一声明元数据、构建后端与工具链配置,是本文各模式真实落地的最佳参照。
核心概念:四个设计原则
在展开具体模式之前,先确立四条贯穿始终的设计原则:
- 模块内聚(Module Cohesion):将“一起变更”的代码组织在一起,一个模块只承担一个清晰、单一的职责。
- 显式接口(Explicit Interfaces):用
__all__声明什么是公开的,凡未列出的成员一律视为内部实现细节。 - 扁平层级(Flat Hierarchies):优先使用浅层目录结构,只有出现真正的子领域时才增加目录深度。
- 一致约定(Consistent Conventions):命名与组织模式在整个项目中统一执行,避免风格漂移。
这四条原则是后面所有具体模式的判断依据:遇到结构决策时,先问自己是否符合内聚、显式、扁平、一致这四条标准。
快速上手:推荐的项目骨架
文档给出的最小可用骨架如下:
myproject/ ├── src/ │ └── myproject/ │ ├── __init__.py │ ├── services/ │ ├── models/ │ └── api/ ├── tests/ ├── pyproject.toml └── README.md这一骨架与仓库中plugin-eval的真实布局完全同构:源码放在src/plugin_eval/下,测试放在平行的tests/目录,项目元数据集中在pyproject.toml。pyproject.toml中通过[tool.hatch.build.targets.wheel] packages = ["src/plugin_eval"]显式指定打包目录,这正是 src 布局在构建配置层面的标准写法。
基础模式:单文件单概念与显式公开 API
Pattern 1:单文件单概念(One Concept Per File)
每个文件只聚焦一个概念或一组紧密相关的函数。当出现以下信号时应考虑拆分文件:
- 文件承担了多个互不相关的职责;
- 文件超过 300~500 行(视复杂度浮动);
- 文件内包含因不同原因而变更的类。
# 好:职责聚焦的文件 # user_service.py - 用户业务逻辑 # user_repository.py - 用户数据访问 # user_models.py - 用户数据结构 # 避免:垃圾桶式文件 # user.py - 同时包含 service、repository、models、utilities...拆分后,职责边界与依赖方向一目了然,修改一个概念时无需在巨大文件中来回滚动。
Pattern 2:用__all__定义显式公开 API
每个模块都应定义公开接口,未列入__all__的成员都是内部实现细节。这样既约束了模块使用者,也让维护者清楚哪些符号可以被安全引用:
# mypackage/services/__init__.py from .user_service import UserService from .order_service import OrderService from .exceptions import ServiceError, ValidationError __all__ = [ "UserService", "OrderService", "ServiceError", "ValidationError", ] # 内部辅助函数通过"不导出"保持私有 # from .internal_helpers import _validate_input # 不导出值得注意的是,__all__机制同样适用于from module import *的导入行为:未列入__all__的成员不会被通配导入,这种“显式优于隐式”的设计天然防止了内部实现被意外暴露。仓库中src/plugin_eval/layers/__init__.py是一个空文件,说明该包刻意不通过包级__init__导出任何符号,而是让使用者从具体子模块(如from plugin_eval.layers.static import StaticAnalyzer)显式导入——这正是“未列出的成员即内部细节”理念的工程体现。
目录结构决策:扁平优先,深度按需
Pattern 3:扁平目录结构
优先采用最少嵌套。过深的层级会让导入语句冗长、导航困难:
# 推荐:扁平结构 project/ ├── api/ │ ├── routes.py │ └── middleware.py ├── services/ │ ├── user_service.py │ └── order_service.py ├── models/ │ ├── user.py │ └── order.py └── utils/ └── validation.py # 避免:过度嵌套 project/core/internal/services/impl/user/只有出现真正需要隔离的子领域时才增加子包。扁平结构意味着模块路径短、导入清晰、重构成本低——移动一个文件通常只需修改少量导入语句。
Pattern 4:测试文件组织策略
文档给出两种方案,核心要求是“全项目二选一并保持一致”:
方案 A:同目录存放(Colocated Tests)
src/ ├── user_service.py ├── test_user_service.py ├── order_service.py └── test_order_service.py优点:测试紧邻被测代码,覆盖盲区一目了然,适合中小项目。
方案 B:平行测试目录(Parallel Test Directory)
src/ ├── services/ │ ├── user_service.py │ └── order_service.py tests/ ├── services/ │ ├── test_user_service.py │ └── test_order_service.py优点:生产代码与测试代码完全分离,是大中型项目的标准做法。仓库的plugin-eval正是方案 B 的忠实实践者:tests/下平铺着test_cli.py、test_engine.py、test_parser.py、test_static.py等与src/plugin_eval/下模块一一对应的测试文件,pyproject.toml中[tool.pytest.ini_options] testpaths = ["tests"]则明确了测试的发现范围。
进阶模式:包初始化、分层架构与领域驱动结构
Pattern 5:包初始化与包级公开接口
用包级__init__.py为包消费者提供干净、统一的人口:
# mypackage/__init__.py """MyPackage - A library for doing useful things.""" from .core import MainClass, HelperClass from .exceptions import PackageError, ConfigError from .config import Settings __all__ = [ "MainClass", "HelperClass", "PackageError", "ConfigError", "Settings", ] __version__ = "1.0.0"消费者因此可以直接从包根导入:
from mypackage import MainClass, Settings仓库中src/plugin_eval/__init__.py就定义并导出了__version__ = "0.1.0"(与pyproject.toml中version = "0.1.0"保持同步),同时以 docstring 简述包定位,是包级初始化文件的极简范本。实际工程中,包级__init__.py还可以承担“薄导出层”职责——只 re-export 稳定接口,避免使用者深入到内部实现路径。
Pattern 6:分层架构(Layered Architecture)
按架构分层组织代码,实现关注点分离:
myapp/ ├── api/ # HTTP 处理器、请求/响应 │ ├── routes/ │ └── middleware/ ├── services/ # 业务逻辑 ├── repositories/ # 数据访问 ├── models/ # 领域实体 ├── schemas/ # API 模式(如 Pydantic) └── config/ # 配置关键约束:每一层只能依赖其下方层级,绝不能反向依赖。这一单向依赖规则保证了变更传播的可控性——修改数据访问层时,业务层接口不变,上层影响面就能被限定。
Pattern 7:领域驱动结构(Domain-Driven Structure)
对于复杂业务应用,按业务领域而非技术层组织代码:
ecommerce/ ├── users/ │ ├── models.py │ ├── services.py │ ├── repository.py │ └── api.py ├── orders/ │ ├── models.py │ ├── services.py │ ├── repository.py │ └── api.py └── shared/ ├── database.py └── exceptions.py领域结构把每个业务域的全部代码收敛在一个目录内,领域内变更不需要跨目录跳跃;shared/只放置跨领域共享的基础设施(数据库会话、公共异常),避免领域之间产生不必要的耦合。分层架构与领域结构并非互斥——实践中常见“领域为外层、层为内层”的混合形态,即每个领域内部再按 api/services/repository 分层。
命名与导入风格约定
文件与模块命名
- 所有文件与模块名使用
snake_case:user_repository.py; - 避免含义晦涩的缩写:
user_repository.py而非usr_repo.py; - 类名与文件名保持一致:
UserService放在user_service.py中。文件名与内容一一对应,是代码可发现性的基础。
导入风格:绝对导入优先
# 推荐:绝对导入 from myproject.services import UserService from myproject.models import User # 避免:相对导入 from ..services import UserService from . import models相对导入在模块被移动或重组时会悄然失效,绝对导入则始终锚定包根,语义更可靠。仓库中src/plugin_eval/engine.py顶部全部使用绝对导入(如from plugin_eval.layers.static import StaticAnalyzer、from plugin_eval.parser import parse_skill),即使该文件与layers/、parser.py同属一个包,也一律从包根plugin_eval.出发——这与文档推荐的导入风格完全一致。
最佳实践总结
- 保持文件聚焦——单文件单概念,超过 300~500 行(视复杂度)考虑拆分;
- 显式定义
__all__——让公开接口清晰可见,未列出即内部实现; - 优先扁平结构——只为真正的子领域增加目录深度;
- 使用绝对导入——更可靠、更清晰;
- 保持一致——命名与组织模式全项目统一;
- 名称匹配内容——文件名应准确描述其用途;
- 分离关注点——保持各层独立,依赖单向流动;
- 文档化结构——用 README 解释项目组织方式,降低新人上手成本。
在真实仓库中的落地验证
以上模式的可行性在 agents 仓库内可以得到直接验证:plugin-eval子项目在pyproject.toml中配置了 hatchling 构建后端与src/打包目录,在src/plugin_eval/下按模块划分cli.py、engine.py、parser.py、corpus.py、stats.py、layers/等功能单元(每个模块职责单一),通过__init__.py暴露版本号,并在平行的tests/目录中用一套测试文件覆盖全部模块。这套结构与本文 Quick Start 骨架一一对应,可作为阅读源码时对照学习的活教材——当你需要为新的 Python 项目做结构决策时,直接套用本文的模式即可获得同样清晰、可维护的代码组织。
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考