Python项目标准目录结构详解:从__init__.py到requirements.txt

Leo
Leo
发布时间:2026-11-15 | 11人浏览过
原创

深入解析现代Python项目的标准目录结构设计,从src布局架构、__init__.py包机制到requirements.txt依赖规范,帮助开发者构建清晰、可维护、易分发的工程化项目。

组织一个规范的 Python 项目并不只是把脚本放进同一个文件夹,而是要为代码导入、依赖隔离、自动化测试以及包分发建立确定性的规则。很多初学者在编写独立脚本时运转正常,但随着模块增多,往往会遭遇混乱的 ModuleNotFoundError、循环依赖导入错误或打包遗漏。本文将围绕现代 Python 项目的标准工程规范展开,从推行 src 架构的深层原因开始,逐一解析从核心包标识 __init__.py 到依赖清单 requirements.txt 的具体职责与实战配置。

一、现代 Python 项目的标准目录全貌:为什么推荐 src 布局?

在早期的 Python 教程中,常见一种“扁平结构”(Flat Layout),即直接将包文件夹与 tests、setup.py 放在项目根目录下。但现代 Python 官方打包规范(PyPA)极力推荐的是 src 布局(src-layout)。下方的树形结构展示了一个工程化标准的 Python 项目全貌:

my_project/
├── src/
│   └── my_project/               # 核心源码包
│       ├── __init__.py           # 声明包命名空间与公开接口
│       ├── core.py               # 核心业务逻辑模块
│       └── utils.py              # 辅助工具模块
├── tests/                        # 测试代码目录(与业务代码隔离)
│   ├── __init__.py               # 测试包标识
│   ├── conftest.py               # pytest 全局共享 fixtures
│   └── test_core.py              # 单元测试用例
├── docs/                         # 项目文档目录
│   └── index.md
├── .gitignore                    # Git 忽略规则文件
├── pyproject.toml                # 现代构建系统与元数据配置(PEP 517/518/621)
├── requirements.txt              # 部署环境生产依赖锁定清单
├── requirements-dev.txt          # 本地开发与测试专用依赖
└── README.md                     # 项目介绍与使用指南

采用 src 布局的核心意义在于解决导入偏见(Import Parity)。在扁平结构中,当你在项目根目录下直接运行测试时,Python 解释器会将当前工作目录自动加入 sys.path 的首位。这会导致解释器优先导入当前源码目录下的代码,即使代码缺少必须的编译扩展、甚至没有正确安装打包,测试也能“侥幸通过”。而在 src 布局下,根目录下没有名为 my_project 的目录,必须先通过 pip install -e . 安装当前包后测试才能正常运行,从而确保了开发测试环境与最终用户的安装环境完全一致。

Python项目标准目录结构详解:从__init__.py到requirements.txt
图 1:现代 Python 工程的物理结构与分层设计优势

二、核心文件深度拆解一:__init__.py 的作用与最佳实践

在 Python 中,包含 __init__.py 的目录会被解释器视作一个常规包(Regular Package)。虽然自 Python 3.3(PEP 420)起引入了隐式命名空间包(Namespace Package),即使没有 __init__.py 目录也可以被导入,但对于绝大多数普通工程而言,显式保留 __init__.py 仍是黄金法则。

1. 它的核心职责是什么?

  • 初始化包作用域:当外部首次执行 import my_project 时,该文件内的顶层代码会被首先执行一次。
  • 定义统一的公开接口(API Gateway):隐藏内部模块的复杂层级,将底层函数和类直接提升到包顶层,方便调用者引用。
  • 明确导出白名单(__all__):严格限制通过 from my_project import * 导出的变量和类,防止内部私有符号意外泄漏。

2. __init__.py 的标准编写范式

假设你的项目结构中有 core.py 和 utils.py,规范的 src/my_project/__init__.py 应该这样编写:

"""MyProject: 高性能工程化 Python 核心工具库."""

__version__ = "1.0.0"

# 从内部子模块导入需要公开给调用者的核心对象
from my_project.core import ProjectManager, TaskRunner
from my_project.utils import format_result

# 显式声明公开接口白名单
__all__ = [
    "__version__",
    "ProjectManager",
    "TaskRunner",
    "format_result",
]

避坑提醒:切勿在 __init__.py 中编写繁重的初始化逻辑(如发起网络请求、读取大型本地配置文件、创建数据库全局连接)。这会导致任何调用者即便仅需导入一个辅助常量,也会被迫触发沉重的冷启动开销。同时,过多的跨模块导入非常容易引发棘手的循环导入错误(Circular Import Error)。

三、核心文件深度拆解二:requirements.txt 与现代依赖管理

在交付或部署 Python 项目时,requirements.txt 是指引 pip 安装依赖的核心清单。然而,许多开发者习惯在终端直接执行 pip freeze > requirements.txt,这往往会导致开发机的临时调试包(如 IPython、Black 等)被无差别写入,造成生产环境体积臃肿与依赖冲突。

Python项目标准目录结构详解:从__init__.py到requirements.txt
图 2:Python 解释器加载常规包与执行 __init__.py 的完整生命周期

1. 依赖分层管理:生产环境与开发环境解耦

工业级实践中,建议将依赖拆分为两个独立文件:

  • requirements.txt(生产部署清单):只包含业务运行所必需的核心依赖,且必须显式锁定全量精确版本号(==),以保障生产部署的确定性与可复现性。
  • requirements-dev.txt(开发测试清单):引入代码格式化、静态检查、测试框架等辅助工具,并通过 -r requirements.txt 继承生产依赖。
# requirements.txt 示例(生产运行依赖,精确版本锁死)
requests==2.31.0
pydantic==2.6.4
fastapi==0.110.0
uvicorn==0.29.0
# requirements-dev.txt 示例(本地开发环境)
-r requirements.txt

pytest==8.1.1
pytest-cov==4.1.0
ruff==0.3.4
mypy==1.9.0

2. requirements.txt 与 pyproject.toml 的分工

很多开发者会产生疑惑:既然现代标准推行 pyproject.toml,为什么还需要 requirements.txt?答案在于“抽象依赖声明”与“具体环境锁定”的区别:

对比维度 pyproject.toml (PEP 621) requirements.txt
核心用途 定义项目的构建系统、元数据及抽象依赖范围。 具体运行环境(Docker、生产虚拟机)的依赖完全锁定。
版本约束风格 范围声明(例如 requests >= 2.28, < 3.0)。 精准锁定(例如 requests == 2.31.0)。
适用场景 发布为可分发的 Python Wheel/Tarball 库。 部署具体的业务终端应用或微服务系统。

四、操作指南:从零搭建标准 Python 工程四步法

理解了各项设计标准后,我们可以通过一套规范的操作流程,在本地终端完整搭建一个标准的 src 架构项目。

Python项目标准目录结构详解:从__init__.py到requirements.txt
图 3:标准 Python 项目初始化四步操作流水线

步骤 1:创建骨架目录与基础文件

在你的工作空间中执行以下命令(执行位置:终端宿主目录):

# 1. 创建工程根目录并进入
mkdir my_project && cd my_project

# 2. 创建 src 目录结构与测试目录
mkdir -p src/my_project tests

# 3. 创建核心文件
touch src/my_project/__init__.py src/my_project/core.py
touch tests/__init__.py tests/test_core.py
touch requirements.txt requirements-dev.txt pyproject.toml README.md .gitignore

步骤 2:配置现代构建规范 pyproject.toml

编辑 pyproject.toml,写入符合 PEP 621 规范的基础配置:

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "my_project"
version = "0.1.0"
description = "一个标准的 Python 工程范例"
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
    "requests>=2.31.0",
]

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]

步骤 3:编写业务代码与单元测试

在 src/my_project/core.py 中实现一个简单的计算函数:

def calculate_tax(amount: float, rate: float = 0.05) -> float:
    """计算含税金额."""
    if amount < 0:
        raise ValueError("金额不能为负数")
    return round(amount * (1 + rate), 2)

在 tests/test_core.py 中编写验证用例:

import pytest
from my_project.core import calculate_tax

def test_calculate_tax_normal():
    assert calculate_tax(100.0, 0.05) == 105.0

def test_calculate_tax_negative():
    with pytest.raises(ValueError, match="金额不能为负数"):
        calculate_tax(-10.0)

步骤 4:安装并执行验证

在项目根目录下通过可编辑模式(Editable Mode)安装当前工程,并运行测试:

# 安装开发模式本地包
pip install -e .

# 安装开发测试依赖
pip install pytest

# 运行自动化测试
pytest

终端预期输出(示例):

============================== test session starts ==============================
platform darwin -- Python 3.10.12, pytest-8.1.1, pluggy-1.4.0
rootdir: /Users/username/my_project
configfile: pyproject.toml
testpaths: tests
collected 2 items

tests/test_core.py ..                                                     [100%]

=============================== 2 passed in 0.03s ===============================

五、避坑指南:四大高频目录与依赖误区排查

误区 1:直接在 src/ 内部运行脚本
很多开发者习惯在终端 cd src/my_project/ 然后运行 python core.py。这会导致解释器将 src/my_project/ 作为搜寻根目录,从而引发 ModuleNotFoundError: No module named 'my_project'。
修复方法:永远在项目根目录下,使用模块化参数运行:python -m my_project.core,或通过 pip install -e . 完成本地挂载后运行。

误区 2:在 .gitignore 中遗漏缓存目录导致污染 Git
Python 运行时会自动在每个包目录下生成 __pycache__/ 目录和 .pyc 字节码文件,虚拟环境目录(如 .venv/)和 pytest 缓存(.pytest_cache/)极易被误提交。
修复方法:在根目录 .gitignore 中务必添加:
__pycache__/、*.py[cod]、.venv/、.pytest_cache/、dist/、build/、*.egg-info/。

误区 3:在 requirements.txt 中过度通配或不锁间接依赖
只写 requests 而不写版本号,当上游依赖发版引入不兼容变更时,CI/CD 流水线或生产 Docker 镜像重新构建会突然崩溃。
修复方法:生产交付请务必锁定固定版本号,推荐配合 pip-tools(pip-compile)自动化生成全量锁定的 requirements.txt。

误区 4:测试文件命名不规范导致 pytest 无法发现用例
pytest 默认通过正则匹配发现用例。如果测试脚本命名为 core_test.py 或类名未大写 Test*,pytest 会直接跳过。
修复方法:测试文件统一以 test_*.py 或 *_test.py 命名,测试函数统一以 test_*() 命名。

六、全景总结:企业级 Python 项目工程资产速查表

为了让读者在实际开发和代码评审时能够快速对照检查,下方的资产速查图与检查表汇总了现代 Python 项目从开发源码到交付分发的全景规范:

Python项目标准目录结构详解:从__init__.py到requirements.txt
图 4:Python 项目工程资产全景与交付规范速查图

工程化落地核对清单

  • 结构 源码位于 src/<package_name>/ 目录,避免采用直接平铺在根目录的扁平结构。
  • 包 核心包及其包含 Python 源码的子目录中均具有明确的 __init__.py 文件。
  • 导出 __init__.py 中定义了 __all__ 白名单,且未包含重度阻塞型网络/磁盘 IO 逻辑。
  • 测试 测试用例存放于根目录 tests/,遵循 test_*.py 命名,并通过 pytest 执行。
  • 依赖 生产环境 requirements.txt 锁死 ==,开发工具单独放入 requirements-dev.txt。
  • 配置 根目录下提供 pyproject.toml 统一声明构建后端及代码分析工具参数。
  • 洁净 .gitignore 已正确配置,确保字节码文件与虚拟环境不会进入版本控制。
相关专题:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表