核心是按业务域而非技术层划分顶层包,如orders/、products/、payments/,各包内聚自身代码并禁止跨域直接导入,依赖通过接口或抽象层单向流动,用__init__.py控制对外API,共享逻辑应独立成包或设shared/目录,辅以自动化检查保障结构健康。

拆分大型 Python 项目包结构,核心是让模块职责清晰、依赖可控、测试可隔离、团队协作顺畅。不是简单按功能建文件夹,而是围绕“可维护性”和“可演进性”设计边界。
按业务域(Domain)而非技术层划分顶层包
避免常见误区:把所有 models 放 models/、所有 views 放 views/——这会导致跨域耦合、迁移困难、领域逻辑被稀释。正确做法是每个核心业务域自成一个子包,内聚其全部相关代码。
-
例如电商项目:划分为
orders/、products/、payments/,每个包含自己的models.py、services.py、api.py、tests/,甚至独立的pyproject.toml(如需单独打包或配置) -
关键约束:包之间禁止直接导入对方的内部模块(如
orders.models不应被products.services导入),通信通过明确定义的接口(如协议类、DTO、事件总线)或公共抽象层
明确分层与依赖方向,用 __init__.py 控制对外接口
每个子包内部可进一步分层(如 domain/、application/、infrastructure/),但必须保证依赖单向流动:上层可依赖下层,下层绝不可反向依赖上层。同时,用 __init__.py 显式导出稳定 API,隐藏实现细节。
-
示例:
orders/__init__.py只写from .application import place_order, cancel_order,不暴露.infrastructure.db或.domain.entities - 好处:外部代码只看到契约,内部重构(比如换数据库驱动)不影响调用方;静态检查工具(如 mypy、pylint)也能更好识别非法引用
提取共享逻辑为独立包,避免隐式复用
当多个业务包出现相似工具函数、通用模型或中间件时,不要复制粘贴,也不要塞进一个模糊的 utils/ 包里。应评估其是否具备独立演进能力——如果它有自己版本号、测试套件、文档,并可能被其他项目复用,就拆成真正的第三方风格包(本地或私有 PyPI)。
立即学习“Python免费学习笔记(深入)”;
- 判断标准:该逻辑是否与任何具体业务域解耦?是否有清晰不变的输入/输出契约?是否需要独立 CI 和发布流程?
-
轻量替代方案:若尚未达到独立包成熟度,可用
shared/目录 +pyproject.toml中配置[tool.setuptools.packages.find]排除它,确保主项目安装时不包含,仅作开发期依赖
自动化验证结构健康度
再好的设计也会随时间退化。加入轻量级检查机制,把架构约束变成可执行规则。
-
禁止跨域导入:用
pydeps或自定义ast脚本扫描,报错提示products.services不得导入orders.models -
检查 public API 稳定性:用
pycln清理未导出的符号;配合pyright的reportUnusedImport防止__init__.py暴露多余内容 - CI 中固化:将这些检查作为 pre-commit hook 和 CI step,失败即阻断合并
不复杂但容易忽略:结构设计不是一次性任务,而是在每次新增功能、重构模块、引入新依赖时持续校验和微调的过程。真正健康的包结构,是让人在阅读 import 语句时,就能自然理解系统边界与协作关系。










