src目录通过将包代码与项目根目录分离,强制要求显式安装或路径配置才能导入,使开发与生产环境行为一致;配合pyproject.toml中packages.find.where=["src"],实现标准化打包、测试和ide支持。

src目录能避免“当前目录导入”导致的包行为不一致
直接把包放在项目根目录下,运行 python main.py 时可能意外成功 import 自己的模块——只因为当前工作目录碰巧是根目录。但用户安装你的包后,import mypackage 就会失败,因为没把根目录加进 sys.path。src 结构天然切断这种侥幸:代码不在 sys.path[0],必须通过正确安装或路径配置才能导入,让开发环境和生产环境行为对齐。
pyproject.toml + src 是现代打包的事实标准
在 pyproject.toml 中只需声明:
[build-system] requires = ["setuptools>=45", "wheel"] build-backend = "setuptools.build_meta" <p>[project] name = "myapp"</p><h1>其他字段...</h1><p>[project.options.packages.find] where = ["src"]</p>
这样 pip install -e . 就会自动从 src/ 下找包,不会误把 tests/、scripts/ 或临时文件打进去。不用再写 setup.py,也不用手动维护 MANIFEST.in 来排除测试文件。
pytest 运行测试时不再需要 hack sys.path
常见错误现象:ModuleNotFoundError: No module named 'myapp',尤其当你在 tests/test_core.py 里写 from myapp.core import do_something 时。
- 错误做法:在
tests/__init__.py里加sys.path.append("../src") - 正确做法:先执行
pip install -e .(一次),之后所有pytest调用都能正常解析绝对导入 - CI/CD 中也只需这一条命令,无需额外路径操作
IDE 和编辑器能更可靠地识别包结构
PyCharm、VS Code 的 Python 插件默认按 src/ 为源根处理——只要你在 pyproject.toml 里配了 where = ["src"],它们就能自动补全、跳转、检查类型,而不会把 tests/ 或 docs/ 当作可导入模块。
容易被忽略的一点是:src 结构本身不解决导入问题,它只是把“必须显式声明包可见性”这个约束提前暴露出来。一旦你接受这个前提,后续的测试、打包、协作就少了很多隐性故障。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











