登录
首页 >  文章 >  python教程

Python项目目录结构常见演变方式

时间:2026-04-29 22:56:56 418浏览 收藏

Python项目目录结构没有放之四海而皆准的“标准”,其演进应由实际工程痛点驱动:src/目录不必初始引入,仅当打包发布失败、CI报错或跨路径导入异常时才需重构;__init__.py虽在Python 3.3+后非绝对必需,但凡涉及相对导入、版本管理或主流打包工具(如PyInstaller、setuptools),就必须保留——哪怕仅声明__version__;tests/理应置于根目录以契合pytest默认行为与CI实践,避免将其混入src导致测试代码被意外安装;配置与静态资源更须与代码物理分离,通过importlib.resources等标准API加载,而非硬编码路径,才能真正适配Docker部署、wheel分发等生产场景——归根结底,目录结构的每一次调整,都该是对下一行报错日志的精准响应。

Python 项目目录结构演进的典型路径

为什么 src/ 目录不是一开始就必须加的

刚跑通第一个 python main.py 时,把所有代码塞进项目根目录完全没问题。这时候加 src/ 反而多一层路径跳转,import 写起来还容易错。等你开始写测试、打包、或者被 CI 报 ModuleNotFoundError 卡住,才是考虑挪进去的信号。

常见错误现象:pytest 能跑通,但 pip install -e . 后在别处 import mypackage 失败;或者 python -m mypackage 提示找不到模块。

  • 真正触发 src/ 的典型场景:需要发布到 PyPI,或团队里有人习惯从任意路径运行你的包
  • setup.pypyproject.tomlpackages=find_packages() 默认不扫描 src/,得显式写成 find_packages(where="src") 并配 package_dir={"": "src"}
  • src/ 后,本地开发时 IDE 可能默认不把 src/ 加进 PYTHONPATH,要手动设或靠 pyproject.toml[tool.setuptools] 配置补上

__init__.py 什么时候可以删、什么时候必须留

Python 3.3+ 支持隐式命名空间包,但现实里删 __init__.py 很容易翻车——尤其当你的包要被 importlib.util.spec_from_file_location 或某些打包工具(如 pyinstaller)处理时。

使用场景差异明显:纯数据包(比如只放 JSON/YAML 配置)可尝试无 __init__.py;但只要涉及 from . import xxx、相对导入、或想用 pkg_resources 查版本,它就得在。

  • 删了 __init__.py 后,pip install -e . 可能成功,但 importlib.import_module("mypackage.submod")ModuleNotFoundError
  • __init__.py 为空文件也行,但建议至少写 __version__ = "0.1.0",方便后续统一管理版本
  • 如果用了 pyproject.toml + setuptools,且包结构是 src/mypackage/__init__.py,那 src/ 下不能有 __init__.py,否则会被当成另一个顶层包

测试目录放哪?tests/src/tests/ 哪个更实际

tests/ 放项目根目录是主流选择,不是因为“规范”,而是因为 pytest 默认就扫这个路径,tox 和 CI 脚本也认它。放进 src/ 里反而让测试变成“被安装的代码”,既没必要又可能引发权限或打包问题。

容易踩的坑在于路径假设:很多新手写 from mypackage import foo 在测试里跑得通,但一换机器或改 sys.path 就崩——其实只是当前工作目录碰巧在项目根下。

  • 确保 pytest 运行时,src/PYTHONPATH 中(推荐用 pyproject.toml[tool.pytest.ini_options]pythonpath = ["src"]
  • 不要在 tests/ 里写 sys.path.insert(0, "../src"),这种硬编码路径在 CI 或不同操作系统下极不可靠
  • 如果真要隔离测试依赖,用 conftest.py 里的 pytest_configure 动态加路径,比改 sys.path 更可控

配置文件和静态资源该不该跟代码混放

开发阶段放一起省事,但上线后,配置(尤其是密钥、环境变量)和静态资源(模板、CSS、图片)必须分离。硬编码路径如 os.path.join(os.path.dirname(__file__), "../config.yaml") 是典型坏味道——一旦打包成 wheel 或用 zipimport__file__ 指向的就是 zip 包内路径,根本找不到上级目录。

真实痛点常出现在 Docker 部署:镜像里只复制了 src/pyproject.toml,结果运行时报 FileNotFoundError: [Errno 2] No such file or directory: 'config.yaml'

  • 配置文件优先走环境变量(os.getenv("DB_URL")),次选命令行参数,最后才读文件;文件路径用 importlib.resources.files("mypackage").joinpath("config.yaml")(Python 3.9+)或 pkg_resources.resource_filename("mypackage", "config.yaml")(兼容旧版)
  • 静态资源(如 Jinja2 模板)别放在 src/mypackage/ 下跟 Python 文件混着,单独建 templates/static/ 根目录,用 importlib.resources 加载
  • 如果用了 MANIFEST.in,记得加 include *.yaml *.j2 *.css,否则 pip install 后这些文件根本不会进安装目录

目录结构不是越“标准”越好,而是越贴近你下一个部署场景越稳。很多人卡在“不知道该不该动”,其实答案就藏在下一次 pip installdocker build 报错的那行日志里。

理论要掌握,实操不能落!以上关于《Python项目目录结构常见演变方式》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>