
Python项目结构与最佳实践一、标准项目结构1.1 小型项目结构myproject/├── README.md├── LICENSE├── setup.py├── requirements.txt├── .gitignore├── myproject/│ ├── __init__.py│ ├── main.py│ └── utils.py└── tests/├── __init__.py└── test_main.py1.2 中型项目结构myproject/├── README.md├── LICENSE├── setup.py├── requirements.txt├── requirements-dev.txt├── .gitignore├── .env.example├── docs/│ ├── conf.py│ └── index.rst├── src/│ └── myproject/│ ├── __init__.py│ ├── cli.py│ ├── config.py│ ├── models/│ │ ├── __init__.py│ │ └── user.py│ ├── services/│ │ ├── __init__.py│ │ └── user_service.py│ └── utils/│ ├── __init__.py│ └── helpers.py└── tests/├── __init__.py├── conftest.py├── unit/│ └── test_user.py└── integration/└── test_user_service.py1.3 大型项目结构myproject/├── README.md├── LICENSE├── CONTRIBUTING.md├── CHANGELOG.md├── setup.py├── pyproject.toml├── requirements/│ ├── base.txt│ ├── dev.txt│ └── prod.txt├── .gitignore├── .env.example├── .github/│ └── workflows/│ └── ci.yml├── docs/│ ├── conf.py│ ├── index.rst│ └── api/├── src/│ └── myproject/│ ├── __init__.py│ ├── __main__.py│ ├── cli/│ ├── api/│ ├── models/│ ├── services/│ ├── repositories/│ ├── utils/│ └── config/├── tests/│ ├── __init__.py│ ├── conftest.py│ ├── unit/│ ├── integration/│ └── e2e/├── scripts/│ ├── setup.sh│ └── deploy.sh└── docker/├── Dockerfile└── docker-compose.yml二、核心文件说明2.1 README.md# 项目名称简短描述项目的功能和目的。## 功能特性- 特性1- 特性2- 特性3## 安装bashpip install myproject## 快速开始pythonfrom myproject import MyClassobj MyClass()obj.do_something()## 文档完整文档请访问: https://myproject.readthedocs.io## 贡献欢迎贡献请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)## 许可证MIT License2.2 setup.pyfrom setuptools import setup, find_packageswith open(README.md, r, encodingutf-8) as fh:long_description fh.read()setup(namemyproject,version0.1.0,authorYour Name,author_emailyouexample.com,descriptionA short description,long_descriptionlong_description,long_description_content_typetext/markdown,urlhttps://github.com/yourusername/myproject,packagesfind_packages(wheresrc),package_dir{: src},classifiers[Development Status :: 3 - Alpha,Intended Audience :: Developers,License :: OSI Approved :: MIT License,Programming Language :: Python :: 3,Programming Language :: Python :: 3.8,Programming Language :: Python :: 3.9,Programming Language :: Python :: 3.10,],python_requires3.8,install_requires[requests2.28.0,click8.0.0,],extras_require{dev: [pytest7.0.0,black22.0.0,flake84.0.0,mypy0.950,],},entry_points{console_scripts: [myprojectmyproject.cli:main,],},)2.3 pyproject.toml[build-system]requires [setuptools45, wheel]build-backend setuptools.build_meta[project]name myprojectversion 0.1.0description A short descriptionreadme README.mdrequires-python 3.8license {text MIT}authors [{name Your Name, email youexample.com}]dependencies [requests2.28.0,click8.0.0,][project.optional-dependencies]dev [pytest7.0.0,black22.0.0,flake84.0.0,][project.scripts]myproject myproject.cli:main[tool.black]line-length 88target-version [py38][tool.isort]profile black[tool.mypy]python_version 3.8warn_return_any truewarn_unused_configs true[tool.pytest.ini_options]testpaths [tests]python_files [test_*.py]2.4 .gitignore# Python__pycache__/*.py[cod]*$py.class*.so.Pythonbuild/develop-eggs/dist/downloads/eggs/.eggs/lib/lib64/parts/sdist/var/wheels/*.egg-info/.installed.cfg*.egg# Virtual environmentsvenv/env/ENV/# IDE.vscode/.idea/*.swp*.swo# Testing.pytest_cache/.coveragehtmlcov/# Environment.env.env.local# OS.DS_StoreThumbs.db三、包和模块组织3.1 __init__.py的使用# src/myproject/__init__.pyMyProject - 项目描述这是项目的主包。__version__ 0.1.0__author__ Your Name# 导出公共APIfrom .main import MyClass, my_function__all__ [MyClass, my_function]3.2 相对导入 vs 绝对导入# 推荐绝对导入from myproject.models.user import Userfrom myproject.services.user_service import UserService# 避免相对导入除非在同一包内from ..models.user import Userfrom .user_service import UserService3.3 循环导入的避免# 不好循环导入# user.pyfrom myproject.services.user_service import UserServiceclass User:def save(self):UserService.save(self)# user_service.pyfrom myproject.models.user import Userclass UserService:staticmethoddef save(user: User):pass# 好使用类型提示的字符串形式# user.pyfrom typing import TYPE_CHECKINGif TYPE_CHECKING:from myproject.services.user_service import UserServiceclass User:def save(self):from myproject.services.user_service import UserServiceUserService.save(self)四、配置管理4.1 使用配置类# config.pyimport osfrom dataclasses import dataclassdataclassclass Config:基础配置DEBUG: bool FalseTESTING: bool FalseSECRET_KEY: str os.getenv(SECRET_KEY, dev-secret-key)DATABASE_URL: str os.getenv(DATABASE_URL, sqlite:///app.db)dataclassclass DevelopmentConfig(Config):开发环境配置DEBUG: bool Truedataclassclass ProductionConfig(Config):生产环境配置DEBUG: bool Falsedataclassclass TestingConfig(Config):测试环境配置TESTING: bool TrueDATABASE_URL: str sqlite:///:memory:# 配置字典config {development: DevelopmentConfig,production: ProductionConfig,testing: TestingConfig,default: DevelopmentConfig}def get_config(envNone):获取配置env env or os.getenv(FLASK_ENV, default)return config[env]()4.2 使用.env文件# .env.exampleDEBUGtrueSECRET_KEYyour-secret-key-hereDATABASE_URLpostgresql://user:passlocalhost/dbnameAPI_KEYyour-api-key# 加载.envfrom dotenv import load_dotenvload_dotenv()五、日志配置5.1 集中式日志配置# logging_config.pyimport loggingimport logging.configLOGGING_CONFIG {version: 1,disable_existing_loggers: False,formatters: {standard: {format: %(asctime)s [%(levelname)s] %(name)s: %(message)s},},handlers: {console: {class: logging.StreamHandler,level: INFO,formatter: standard,stream: ext://sys.stdout},file: {class: logging.handlers.RotatingFileHandler,level: DEBUG,formatter: standard,filename: logs/app.log,maxBytes: 10485760,backupCount: 5}},loggers: {: {level: INFO,handlers: [console, file]},myproject: {level: DEBUG,handlers: [console, file],propagate: False}}}def setup_logging():logging.config.dictConfig(LOGGING_CONFIG)六、测试组织6.1 测试结构tests/├── __init__.py├── conftest.py # pytest fixtures├── unit/ # 单元测试│ ├── __init__.py│ ├── test_models.py│ └── test_services.py├── integration/ # 集成测试│ ├── __init__.py│ └── test_api.py└── e2e/ # 端到端测试├── __init__.py└── test_workflows.py6.2 conftest.py# tests/conftest.pyimport pytestfrom myproject import create_appfrom myproject.database import dbpytest.fixturedef app():创建测试应用app create_app(testing)with app.app_context():db.create_all()yield appdb.drop_all()pytest.fixturedef client(app):创建测试客户端return app.test_client()pytest.fixturedef sample_user():创建示例用户return {username: testuser,email: testexample.com}七、文档组织7.1 使用Sphinx# docs/conf.pyproject MyProjectcopyright 2024, Your Nameauthor Your Nameextensions [sphinx.ext.autodoc,sphinx.ext.napoleon,sphinx.ext.viewcode,]html_theme sphinx_rtd_theme7.2 文档字符串def calculate_total(items: list, tax_rate: float 0.1) - float:计算订单总额。Args:items: 订单项目列表每个项目包含price和quantitytax_rate: 税率默认为0.110%Returns:包含税费的订单总额Raises:ValueError: 如果items为空或tax_rate为负数Example: items [{price: 10, quantity: 2}] calculate_total(items)22.0if not items:raise ValueError(订单项目不能为空)if tax_rate 0:raise ValueError(税率不能为负数)subtotal sum(item[price] * item[quantity] for item in items)return subtotal * (1 tax_rate)八、依赖管理8.1 requirements文件组织# requirements/base.txtrequests2.28.0click8.0.0python-dotenv0.20.0# requirements/dev.txt-r base.txtpytest7.0.0pytest-cov3.0.0black22.0.0flake84.0.0mypy0.950# requirements/prod.txt-r base.txtgunicorn20.1.08.2 使用pip-tools# 安装pip install pip-tools# requirements.inrequestsclickpython-dotenv# 生成锁定文件pip-compile requirements.in# 安装pip-sync requirements.txt九、CI/CD配置9.1 GitHub Actions# .github/workflows/ci.ymlname: CIon: [push, pull_request]jobs:test:runs-on: ubuntu-lateststrategy:matrix:python-version: [3.8, 3.9, 3.10]steps:- uses: actions/checkoutv2- name: Set up Python ${{ matrix.python-version }}uses: actions/setup-pythonv2with:python-version: ${{ matrix.python-version }}- name: Install dependenciesrun: |python -m pip install --upgrade pippip install -r requirements/dev.txt- name: Lintrun: |flake8 src testsblack --check src testsmypy src- name: Testrun: |pytest --covmyproject tests/- name: Upload coverageuses: codecov/codecov-actionv2十、Docker化10.1 Dockerfile# DockerfileFROM python:3.10-slimWORKDIR /app# 安装依赖COPY requirements/prod.txt requirements.txtRUN pip install --no-cache-dir -r requirements.txt# 复制代码COPY src/ .# 创建非root用户RUN useradd -m -u 1000 appuser chown -R appuser:appuser /appUSER appuser# 暴露端口EXPOSE 8000# 启动命令CMD [gunicorn, --bind, 0.0.0.0:8000, myproject.wsgi:app]10.2 docker-compose.ymlversion: 3.8services:web:build: .ports:- 8000:8000environment:- DATABASE_URLpostgresql://user:passdb:5432/mydbdepends_on:- dbdb:image: postgres:14environment:- POSTGRES_USERuser- POSTGRES_PASSWORDpass- POSTGRES_DBmydbvolumes:- postgres_data:/var/lib/postgresql/datavolumes:postgres_data:十一、版本控制最佳实践11.1 .gitignore模板# 使用gitignore.io生成# https://www.toptal.com/developers/gitignore/api/python11.2 提交消息规范# 格式():# 类型feat: 新功能fix: 修复bugdocs: 文档更新style: 代码格式refactor: 重构test: 测试chore: 构建/工具# 示例feat(auth): 添加JWT认证实现了基于JWT的用户认证系统包括- 登录端点- 令牌刷新- 令牌验证中间件Closes #123十二、项目检查清单- [ ] README.md完整- [ ] LICENSE文件- [ ] .gitignore配置- [ ] requirements.txt- [ ] 测试覆盖率80%- [ ] CI/CD配置- [ ] 文档完整- [ ] 类型提示- [ ] 日志配置- [ ] 错误处理- [ ] 安全检查- [ ] 性能测试- [ ] Docker化- [ ] 环境变量配置十三、总结良好的项目结构是可维护代码的基础。遵循标准的目录布局合理组织代码配置完善的开发工具链可以大大提高开发效率和代码质量。记住项目结构应该随着项目规模的增长而演进从简单开始逐步完善。