98_Python项目结构最佳实践
Python项目结构最佳实践文章目录Python项目结构最佳实践前言一、标准目录结构为什么推荐 src 布局二、配置文件详解pyproject.toml推荐.gitignore 模板三、核心模块设计__main__.py支持直接运行包config.py集中配置管理四、编写优秀的 README基本用法开发指南许可证六、\_\_init\_\_.py 的使用原则七、测试结构总结亮点总结适用场景扩展方向前言一个 Python 脚本可能只需要一个.py文件就能运行但一个专业的 Python 项目则需要清晰的目录结构、合理的模块划分、规范的依赖管理以及完善的文档体系。良好的项目结构不仅能让自己在几个月后还能快速理解代码更是团队协作的基础。许多新手在从写脚本过渡到写项目时最大的困惑不是怎么写代码而是把代码放在哪里——模块应该如何划分测试应该放哪里配置文件放根目录还是包内面试常见考点src布局 vs 传统布局的区别和优劣、pyproject.toml的用途、__init__.py在包中的角色、__main__.py的作用、为什么要把依赖分离为production和dev。面试官可能给一个杂乱的项目结构让你挑毛病考察你对工程规范的敏感度。本文将分享经过社区验证的 Python 项目结构最佳实践包括目录布局、模块划分、打包配置和 README 编写规范。一、标准目录结构一个成熟的 Python 项目通常采用以下结构myproject/ ├── README.md # 项目说明文档 ├── LICENSE # 开源许可证 ├── pyproject.toml # 现代打包配置推荐 ├── setup.py # 传统打包配置兼容 ├── requirements.txt # 生产依赖 ├── requirements-dev.txt # 开发依赖 ├── .gitignore # Git 忽略文件 │ ├── src/ # src 布局推荐 │ └── myproject/ │ ├── __init__.py │ ├── __main__.py # 支持 python -m myproject │ ├── config.py # 配置管理 │ ├── core/ # 核心业务逻辑 │ │ ├── __init__.py │ │ ├── engine.py │ │ └── models.py │ ├── utils/ # 工具函数 │ │ ├── __init__.py │ │ ├── helpers.py │ │ └── validators.py │ └── cli/ # 命令行接口 │ ├── __init__.py │ ├── commands.py │ └── parser.py │ ├── tests/ # 测试代码 │ ├── __init__.py │ ├── conftest.py # pytest 配置 │ ├── test_core/ │ │ ├── __init__.py │ │ └── test_engine.py │ └── test_utils/ │ ├── __init__.py │ └── test_helpers.py │ ├── docs/ # 文档 │ ├── index.md │ ├── api.md │ └── examples.md │ └── scripts/ # 辅助脚本 ├── setup_db.py └── seed_data.py为什么推荐 src 布局传统布局将包直接放在项目根目录容易导致导入混淆——Python 可能导入的是项目目录下的代码而非安装的包。这是一个隐蔽的问题在开发环境下你导入了项目根目录的代码能跑但在用户安装你的包后导入路径发生变化可能导致ImportError。src布局强制开发者先安装项目pip install -e .才能进行测试从而确保测试时使用与用户相同的安装方式。这就像模拟真实用户环境的测试——你在开发时就发现安装相关的问题而不是等到用户报告。# 传统布局不推荐 myproject/ ├── myproject/ # 包直接在根目录 │ └── ... └── tests/ # src 布局推荐 myproject/ ├── src/ │ └── myproject/ # 包在 src 中 └── tests/二、配置文件详解pyproject.toml推荐[build-system] requires [setuptools61.0, wheel] build-backend setuptools.build_meta [project] name myproject version 0.1.0 description 一个示例 Python 项目 readme README.md authors [ {name Your Name, email youexample.com}, ] license {text MIT} classifiers [ Programming Language :: Python :: 3, Programming Language :: Python :: 3.9, Programming Language :: Python :: 3.10, Programming Language :: Python :: 3.11, License :: OSI Approved :: MIT License, Operating System :: OS Independent, ] requires-python 3.9 dependencies [ requests2.28, click8.0, pyyaml6.0, ] [project.optional-dependencies] dev [ pytest7.0, pytest-cov4.0, black23.0, ruff0.1, mypy1.0, ] [project.scripts] myproject myproject.cli.commands:main [tool.setuptools.packages.find] where [src] [tool.pytest.ini_options] testpaths [tests] addopts -v --tbshort [tool.black] line-length 100 [tool.ruff] line-length 100 select [E, F, I, N, W].gitignore 模板__pycache__/ *.py[cod] *.egg-info/ dist/ build/ .venv/ venv/ .env *.log .coverage .pytest_cache/ .mypy_cache/三、核心模块设计__main__.py支持直接运行包# src/myproject/__main__.py支持 python -m myproject 运行frommyproject.cli.commandsimportmainif__name____main__:main()config.py集中配置管理# src/myproject/config.pyimportosfrompathlibimportPathclassConfig:应用配置支持环境变量覆盖BASE_DIRPath(__file__).resolve().parent.parent.parent# 数据库配置DB_HOSTos.getenv(MYPROJECT_DB_HOST,localhost)DB_PORTint(os.getenv(MYPROJECT_DB_PORT,5432))DB_NAMEos.getenv(MYPROJECT_DB_NAME,myproject_db)DB_USERos.getenv(MYPROJECT_DB_USER,postgres)DB_PASSWORDos.getenv(MYPROJECT_DB_PASSWORD,)classmethoddefdatabase_url(cls):return(fpostgresql://{cls.DB_USER}:{cls.DB_PASSWORD}f{cls.DB_HOST}:{cls.DB_PORT}/{cls.DB_NAME})# 日志配置LOG_LEVELos.getenv(MYPROJECT_LOG_LEVEL,INFO)LOG_FILEos.getenv(MYPROJECT_LOG_FILE,str(BASE_DIR/app.log))# API 配置API_TIMEOUTint(os.getenv(MYPROJECT_API_TIMEOUT,30))MAX_RETRIESint(os.getenv(MYPROJECT_MAX_RETRIES,3))四、编写优秀的 READMEREADME 是项目的门面好的 README 应包含以下要素# MyProject 简短的一句话描述项目的用途和价值。 ## 功能特性 - 功能一描述 - 功能二描述 - 功能三描述 ## 快速开始 ### 安装 bash pip install myproject基本用法frommyproject.engineimportMyEngine engineMyEngine()resultengine.process(input)print(result)开发指南gitclone https://github.com/you/myproject.gitcdmyproject pipinstall-e.[dev]pytest许可证MIT License## 五、依赖管理策略 依赖管理是项目工程化的核心环节。一个常见的反模式是只维护一个 requirements.txt不区分生产依赖和开发依赖导致部署时安装了不必要的测试框架。在部署环境中减少依赖就是减少攻击面和不必要的构建时间。 ### requirements.txt vs pyproject.toml txt # requirements.txt — 精确版本锁定版本 requests2.31.0 click8.1.7 pyyaml6.0.1 # requirements-dev.txt -r requirements.txt pytest7.4.3 black23.11.0 ruff0.1.8推荐做法pyproject.toml声明宽松的依赖范围requirements.txt锁定精确版本用于部署使用pip freeze requirements.txt生成锁定文件使用Poetry或PDM获得类似 npm/yarn 的依赖管理体验六、__init__.py 的使用原则# src/myproject/__init__.py myproject - 项目简短描述 __version__0.1.0__author__Your Name# 有选择性地暴露公共 APIfrommyproject.core.engineimportMyEnginefrommyproject.core.modelsimportDataModel __all__[MyEngine,DataModel]原则__init__.py中只暴露最重要的公共 API避免全部导入影响加载速度tests/__init__.py保持为空或只放测试相关的共享 fixture七、测试结构# tests/conftest.pyimportpytestpytest.fixturedefsample_data():共享测试数据return{id:1,name:test,items:[1,2,3]}pytest.fixturedeftemp_dir(tmp_path):使用 pytest 内置临时目录returntmp_path# tests/test_core/test_engine.pyfrommyproject.core.engineimportMyEnginedeftest_engine_init():engineMyEngine()assertengineisnotNonedeftest_process_with_data(sample_data):engineMyEngine()resultengine.process(sample_data)assertresult[status]success总结良好的项目结构是软件工程质量的基石。本文推荐的src 布局解决了导入混淆问题pyproject.toml统一了构建配置和依赖声明config.py实现了环境感知的配置管理。测试代码与源码分离、文档与代码同行这些实践经过了数千个开源项目的验证。无论项目大小从一开始就采用规范结构远比后期重构要轻松得多。建议创建一个项目模板仓库作为新项目的起点。亮点总结标准目录结构全览从 src 布局到核心模块core/utils/cli、测试目录tests/conftest.py、文档目录docs/和脚本目录scripts/形成完整的项目骨架。pyproject.toml 全面配置打包元数据、依赖声明、开发依赖分组、命令行入口点、以及 Black/Ruff/pytest 的工具配置集中管理在一份文件中。核心模块设计示范__main__.py支持python -m运行、config.py集中管理环境变量、__init__.py有选择性地暴露公共 API每个模块都有明确职责。测试与源码分离conftest.py 共享 fixture、pytest 配置集中管理、测试目录结构与源码一一对应形成可维护的测试体系。README 编写规范功能特性、快速开始、开发指南、许可证——四要素构成一个有吸引力的项目门面。适用场景新项目从零搭建按照本文的目录布局和配置文件直接复用几分钟内完成项目初始化告别随意堆积文件的混乱状态。开源项目目录规划在 GitHub 上发布开源项目前使用 src 布局 pyproject.toml 完善的 README给使用者留下专业的第一印象。团队项目管理标准化统一团队内部的项目结构规范新人 clone 后能快速定位代码位置减少适应成本。扩展方向Python 虚拟环境与依赖管理本系列第 90 篇在项目结构中集成 Poetry 或 pip-tools将 pyproject.toml 的依赖声明与虚拟环境管理联动。Python 代码规范与风格指南本系列第 89 篇将 Black isort Ruff 的配置融入 pyproject.toml在项目结构中实现代码风格的自动化管理。CI/CD 流水线与 Makefile在项目根目录添加 Makefile 统一常用命令make install/make test/make lint并学习 GitHub Actions 将测试和代码检查集成到提交流程中。