python-project-structure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePython Project Structure & Module Architecture
Python项目结构与模块架构
Design well-organized Python projects with clear module boundaries, explicit public interfaces, and maintainable directory structures. Good organization makes code discoverable and changes predictable.
设计组织良好的Python项目,具备清晰的模块边界、明确的公共接口和可维护的目录结构。良好的项目组织能让代码更易查找,变更更可预测。
When to Use This Skill
何时使用该方法
- Starting a new Python project from scratch
- Reorganizing an existing codebase for clarity
- Defining module public APIs with
__all__ - Deciding between flat and nested directory structures
- Determining test file placement strategies
- Creating reusable library packages
- 从零开始新建Python项目
- 重构现有代码库以提升清晰度
- 使用定义模块公共API
__all__ - 选择扁平化或嵌套式目录结构
- 确定测试文件的放置策略
- 创建可复用的库包
Core Concepts
核心概念
1. Module Cohesion
1. 模块内聚性
Group related code that changes together. A module should have a single, clear purpose.
将相关且会同步变更的代码归为一组。每个模块应具备单一、明确的用途。
2. Explicit Interfaces
2. 明确的接口
Define what's public with . Everything not listed is an internal implementation detail.
__all__使用定义公共内容。未列出的所有内容均为内部实现细节。
__all__3. Flat Hierarchies
3. 扁平化层级
Prefer shallow directory structures. Add depth only for genuine sub-domains.
优先采用浅层次目录结构。仅当存在真正的子领域时才增加层级深度。
4. Consistent Conventions
4. 一致的约定
Apply naming and organization patterns uniformly across the project.
在项目中统一应用命名和组织模式。
Quick Start
快速开始
myproject/
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── services/
│ ├── models/
│ └── api/
├── tests/
├── pyproject.toml
└── README.mdmyproject/
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── services/
│ ├── models/
│ └── api/
├── tests/
├── pyproject.toml
└── README.mdFundamental Patterns
基础模式
Pattern 1: One Concept Per File
模式1:每个文件对应一个概念
Each file should focus on a single concept or closely related set of functions. Consider splitting when a file:
- Handles multiple unrelated responsibilities
- Grows beyond 300-500 lines (varies by complexity)
- Contains classes that change for different reasons
python
undefined每个文件应聚焦于单个概念或一组紧密相关的函数。当文件出现以下情况时,考虑拆分:
- 处理多个不相关的职责
- 代码行数超过300-500行(根据复杂度有所不同)
- 包含因不同原因而变更的类
python
undefinedGood: Focused files
良好示例:聚焦单一的文件
user_service.py - User business logic
user_service.py - 用户业务逻辑
user_repository.py - User data access
user_repository.py - 用户数据访问
user_models.py - User data structures
user_models.py - 用户数据结构
Avoid: Kitchen sink files
避免:全能型文件
user.py - Contains service, repository, models, utilities...
user.py - 包含服务、数据访问、模型、工具等...
undefinedundefinedPattern 2: Explicit Public APIs with __all__
__all__模式2:使用__all__
定义明确的公共API
__all__Define the public interface for every module. Unlisted members are internal implementation details.
python
undefined为每个模块定义公共接口。未列出的成员均为内部实现细节。
python
undefinedmypackage/services/init.py
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 .user_service import UserService
from .order_service import OrderService
from .exceptions import ServiceError, ValidationError
all = [
"UserService",
"OrderService",
"ServiceError",
"ValidationError",
]
Internal helpers remain private by omission
内部工具默认保持私有
from .internal_helpers import _validate_input # Not exported
from .internal_helpers import _validate_input # 未导出
undefinedundefinedPattern 3: Flat Directory Structure
模式3:扁平化目录结构
Prefer minimal nesting. Deep hierarchies make imports verbose and navigation difficult.
undefined优先采用最少嵌套的结构。过深的层级会导致导入语句冗长,且难以导航。
undefinedPreferred: Flat structure
推荐:扁平化结构
project/
├── api/
│ ├── routes.py
│ └── middleware.py
├── services/
│ ├── user_service.py
│ └── order_service.py
├── models/
│ ├── user.py
│ └── order.py
└── utils/
└── validation.py
project/
├── api/
│ ├── routes.py
│ └── middleware.py
├── services/
│ ├── user_service.py
│ └── order_service.py
├── models/
│ ├── user.py
│ └── order.py
└── utils/
└── validation.py
Avoid: Deep nesting
避免:过深的嵌套
project/core/internal/services/impl/user/
Add sub-packages only when there's a genuine sub-domain requiring isolation.project/core/internal/services/impl/user/
仅当存在需要隔离的真正子领域时,才添加子包。Pattern 4: Test File Organization
模式4:测试文件组织
Choose one approach and apply it consistently throughout the project.
Option A: Colocated Tests
src/
├── user_service.py
├── test_user_service.py
├── order_service.py
└── test_order_service.pyBenefits: Tests live next to the code they verify. Easy to see coverage gaps.
Option B: Parallel Test Directory
src/
├── services/
│ ├── user_service.py
│ └── order_service.py
tests/
├── services/
│ ├── test_user_service.py
│ └── test_order_service.pyBenefits: Clean separation between production and test code. Standard for larger projects.
选择一种方式并在整个项目中一致应用。
选项A:测试文件与代码同目录
src/
├── user_service.py
├── test_user_service.py
├── order_service.py
└── test_order_service.py优势:测试文件紧邻其验证的代码。易于发现覆盖缺口。
选项B:平行测试目录
src/
├── services/
│ ├── user_service.py
│ └── order_service.py
tests/
├── services/
│ ├── test_user_service.py
│ └── test_order_service.py优势:清晰分离生产代码与测试代码。是大型项目的标准做法。
Advanced Patterns
进阶模式
Pattern 5: Package Initialization
模式5:包初始化
Use to provide a clean public interface for package consumers.
__init__.pypython
undefined使用为包使用者提供简洁的公共接口。
__init__.pypython
undefinedmypackage/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"
Consumers can then import directly from the package:
```python
from mypackage import MainClass, Settings"""MyPackage - 一个用于实现实用功能的库。"""
from .core import MainClass, HelperClass
from .exceptions import PackageError, ConfigError
from .config import Settings
all = [
"MainClass",
"HelperClass",
"PackageError",
"ConfigError",
"Settings",
]
version = "1.0.0"
使用者随后可以直接从包导入:
```python
from mypackage import MainClass, SettingsPattern 6: Layered Architecture
模式6:分层架构
Organize code by architectural layer for clear separation of concerns.
myapp/
├── api/ # HTTP handlers, request/response
│ ├── routes/
│ └── middleware/
├── services/ # Business logic
├── repositories/ # Data access
├── models/ # Domain entities
├── schemas/ # API schemas (Pydantic)
└── config/ # ConfigurationEach layer should only depend on layers below it, never above.
按架构层组织代码,实现清晰的关注点分离。
myapp/
├── api/ # HTTP处理器、请求/响应
│ ├── routes/
│ └── middleware/
├── services/ # 业务逻辑
├── repositories/ # 数据访问
├── models/ # 领域实体
├── schemas/ # API模式(Pydantic)
└── config/ # 配置每个层应仅依赖于其下方的层,绝不能依赖上方的层。
Pattern 7: Domain-Driven Structure
模式7:领域驱动结构
For complex applications, organize by business domain rather than technical layer.
ecommerce/
├── users/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
├── orders/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
└── shared/
├── database.py
└── exceptions.py对于复杂应用,按业务领域而非技术层进行组织。
ecommerce/
├── users/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
├── orders/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
└── shared/
├── database.py
└── exceptions.pyFile and Module Naming
文件与模块命名
Conventions
约定
- Use for all file and module names:
snake_caseuser_repository.py - Avoid abbreviations that obscure meaning: not
user_repository.pyusr_repo.py - Match class names to file names: in
UserServiceuser_service.py
- 所有文件和模块名称使用命名法:
snake_caseuser_repository.py - 避免使用会模糊含义的缩写:使用而非
user_repository.pyusr_repo.py - 类名与文件名匹配:位于
UserService中user_service.py
Import Style
导入风格
Use absolute imports for clarity and reliability:
python
undefined使用绝对导入以确保清晰性和可靠性:
python
undefinedPreferred: Absolute imports
推荐:绝对导入
from myproject.services import UserService
from myproject.models import User
from myproject.services import UserService
from myproject.models import User
Avoid: Relative imports
避免:相对导入
from ..services import UserService
from . import models
Relative imports can break when modules are moved or reorganized.from ..services import UserService
from . import models
相对导入在模块被移动或重组时可能会失效。Best Practices Summary
最佳实践总结
- Keep files focused - One concept per file, consider splitting at 300-500 lines (varies by complexity)
- Define explicitly - Make public interfaces clear
__all__ - Prefer flat structures - Add depth only for genuine sub-domains
- Use absolute imports - More reliable and clearer
- Be consistent - Apply patterns uniformly across the project
- Match names to content - File names should describe their purpose
- Separate concerns - Keep layers distinct and dependencies flowing one direction
- Document your structure - Include a README explaining the organization
- 保持文件聚焦 - 每个文件对应一个概念,当代码行数达到300-500行时考虑拆分(根据复杂度有所不同)
- 明确定义- 让公共接口清晰可见
__all__ - 优先采用扁平化结构 - 仅当存在真正的子领域时才增加层级深度
- 使用绝对导入 - 更可靠且更清晰
- 保持一致性 - 在项目中统一应用模式
- 名称与内容匹配 - 文件名应描述其用途
- 分离关注点 - 保持各层独立,依赖关系单向流动
- 记录你的结构 - 在README中说明项目组织方式